feat(rack-planner): add support for WAN and SFP ports with right-justified layout and distinct styling

This commit is contained in:
2026-03-22 15:16:54 -05:00
parent b26f88a89e
commit 1f360cdb2a
6 changed files with 162 additions and 59 deletions

View File

@@ -5,7 +5,7 @@ export type ModuleType =
| 'SWITCH' | 'AGGREGATE_SWITCH' | 'MODEM' | 'ROUTER' | 'NAS'
| 'PDU' | 'PATCH_PANEL' | 'SERVER' | 'FIREWALL' | 'AP' | 'BLANK' | 'OTHER';
export type PortType = 'ETHERNET' | 'SFP' | 'SFP_PLUS' | 'QSFP' | 'CONSOLE' | 'UPLINK';
export type PortType = 'ETHERNET' | 'SFP' | 'SFP_PLUS' | 'QSFP' | 'CONSOLE' | 'UPLINK' | 'WAN';
export type VlanMode = 'ACCESS' | 'TRUNK' | 'HYBRID';

View File

@@ -47,6 +47,8 @@ export async function createModule(
notes?: string;
portCount?: number;
portType?: PortType;
sfpCount?: number;
wanCount?: number;
}
) {
const rack = await prisma.rack.findUnique({ where: { id: rackId } });
@@ -66,8 +68,32 @@ export async function createModule(
throw new AppError('U-slot collision: another module occupies that space', 409, 'COLLISION');
}
const portCount = data.portCount ?? MODULE_PORT_DEFAULTS[data.type] ?? 0;
const portType: PortType = data.portType ?? 'ETHERNET';
const sfpCount = data.sfpCount ?? (data.type === 'AGGREGATE_SWITCH' ? data.portCount ?? MODULE_PORT_DEFAULTS[data.type] : 0);
const wanCount = data.wanCount ?? 0;
// If aggregate switch is chosen, it usually uses its portCount as SFP ports, but it can be overridden.
// Standard ethernet port count is either the provided portCount or the default, adjusted if it's an aggregate switch (where default are SFP)
const ethernetCount = data.type === 'AGGREGATE_SWITCH'
? (data.portCount ? data.portCount : 0) // if user manually set portCount for Aggr, we treat it as ethernet (unlikely but possible)
: (data.portCount ?? MODULE_PORT_DEFAULTS[data.type] ?? 0);
const portsToCreate = [];
let currentNum = 1;
// 1. WAN/Uplink ports (often on the left or special)
for (let i = 0; i < wanCount; i++) {
portsToCreate.push({ portNumber: currentNum++, portType: 'WAN' as PortType });
}
// 2. Standard Ethernet ports
for (let i = 0; i < ethernetCount; i++) {
if (data.type === 'AGGREGATE_SWITCH' && !data.portCount) break; // skip if it's aggr and we handle them as SFPs below
portsToCreate.push({ portNumber: currentNum++, portType: 'ETHERNET' as PortType });
}
// 3. SFP ports
for (let i = 0; i < sfpCount; i++) {
portsToCreate.push({ portNumber: currentNum++, portType: 'SFP' as PortType });
}
return prisma.module.create({
data: {
@@ -81,10 +107,7 @@ export async function createModule(
ipAddress: data.ipAddress,
notes: data.notes,
ports: {
create: Array.from({ length: portCount }, (_, i) => ({
portNumber: i + 1,
portType,
})),
create: portsToCreate,
},
},
include: moduleInclude,