Added fields for managed info

This commit is contained in:
2026-05-14 18:22:01 -05:00
parent dd8e1b2418
commit d077c68e96
4 changed files with 85 additions and 2 deletions

View File

@@ -37,6 +37,11 @@ Datacenter Modeler is a React-based web application for designing datacenter rac
- Edit component port-map properties for Switch, Firewall, Storage Switch, Router, Server, Blade Chassis, Storage Array, and KVM:
- Dynamic port map with Port ID, Cable ID, and VLAN fields
- VLAN defaults to 1 for new component ports
- Edit managed-device properties for Switch, Firewall, Storage Switch, Router, Server, Blade Chassis, Storage Array, and KVM:
- Managed status
- IP address/hostname
- URL
- User
- Edit PDU-specific properties:
- Horizontal rack mount or vertical side mount
- Horizontal size from 1U to 12U
@@ -149,7 +154,7 @@ Diagram data is stored as JSON with this top-level shape:
}
```
Each rack/cabinet contains its own metadata and an array of installed equipment. Equipment records include type, name, size, U position, manufacturer/model details, asset information, power, notes, and display color. Patch panel and network-capable component records also include structured port map metadata. PDU records include mounting orientation, side placement for vertical PDUs, input voltage, output port definitions, and managed-device connection metadata.
Each rack/cabinet contains its own metadata and an array of installed equipment. Equipment records include type, name, size, U position, manufacturer/model details, asset information, power, notes, and display color. Patch panel and network-capable component records also include structured port map metadata. Network-capable components and PDUs can store managed-device connection metadata.
## Project Structure

View File

@@ -536,6 +536,10 @@ export default function App() {
? ` | ${item.patchPanelMedium === 'fiberoptic' ? 'Fiber optic' : 'Copper'} | ${item.patchPanelPorts} ports | ${item.patchPanelPortMap.length} mapped`
: '';
const networkPortDetails = PORT_MAPPED_COMPONENTS.has(item.type) ? ` | ${item.networkPorts.length} mapped ports` : '';
const managedDetails =
PORT_MAPPED_COMPONENTS.has(item.type) && item.managed
? ` | Managed ${item.managedHostname || 'no host'}`
: '';
const pduDetails =
item.type === 'pdu'
? ` | ${item.pduMount === 'vertical' ? `Vertical ${item.pduSide}, ${item.sizeU}U wide` : `Horizontal ${item.sizeU}U`} | In ${item.pduInputVoltage || 'n/a'} | ${item.pduOutputPorts.length} outputs${item.pduManaged ? ` | Managed ${item.pduHostname || 'no host'}` : ''}`
@@ -544,7 +548,7 @@ export default function App() {
item.type === 'pdu' && item.pduMount === 'vertical'
? `${item.pduSide === 'left' ? 'Left' : 'Right'} side`
: `U${item.uStart}-${item.uStart + item.sizeU - 1}`;
const line = `${rackPosition}: ${item.name} | ${item.manufacturer || 'n/a'} ${item.model || ''} | ${item.assetTag || 'no asset tag'}${patchPanelDetails}${networkPortDetails}${pduDetails}`;
const line = `${rackPosition}: ${item.name} | ${item.manufacturer || 'n/a'} ${item.model || ''} | ${item.assetTag || 'no asset tag'}${patchPanelDetails}${networkPortDetails}${managedDetails}${pduDetails}`;
pdf.text(line.slice(0, 115), margin + 12, y);
y += 14;
});
@@ -1443,6 +1447,68 @@ function PropertiesPanel({
</Stack>
</>
)}
{PORT_MAPPED_COMPONENTS.has(selectedEquipment.type) && (
<>
<Divider />
<Typography variant="subtitle2" sx={{ fontWeight: 800 }}>
Managed Device
</Typography>
<Box>
<Typography variant="body2" sx={{ fontWeight: 800 }}>
Managed
</Typography>
<Slider
value={selectedEquipment.managed ? 1 : 0}
min={0}
max={1}
step={1}
marks={[
{ value: 0, label: 'No' },
{ value: 1, label: 'Yes' },
]}
onChange={(_, value) =>
onEquipmentChange(selectedEquipmentRack.id, selectedEquipment.id, {
managed: (value as number) === 1,
})
}
/>
</Box>
{selectedEquipment.managed && (
<>
<TextField
label="IP address / hostname"
value={selectedEquipment.managedHostname}
onChange={(event) =>
onEquipmentChange(selectedEquipmentRack.id, selectedEquipment.id, {
managedHostname: event.target.value,
})
}
fullWidth
/>
<TextField
label="URL"
value={selectedEquipment.managedUrl}
onChange={(event) =>
onEquipmentChange(selectedEquipmentRack.id, selectedEquipment.id, {
managedUrl: event.target.value,
})
}
fullWidth
/>
<TextField
label="User"
value={selectedEquipment.managedUser}
onChange={(event) =>
onEquipmentChange(selectedEquipmentRack.id, selectedEquipment.id, {
managedUser: event.target.value,
})
}
fullWidth
/>
</>
)}
</>
)}
{selectedEquipment.type === 'pdu' && (
<>
<Divider />

View File

@@ -69,6 +69,10 @@ export interface Equipment {
patchPanelPorts: number;
patchPanelPortMap: PatchPanelPort[];
networkPorts: NetworkPort[];
managed: boolean;
managedHostname: string;
managedUrl: string;
managedUser: string;
pduMount: PduMount;
pduSide: PduSide;
pduInputVoltage: string;

View File

@@ -57,6 +57,10 @@ export const createEquipment = (type: string, rack: RackContainer, preferredU: n
patchPanelPorts: libraryItem.type === 'patch-panel' ? 24 : 0,
patchPanelPortMap: [],
networkPorts: [],
managed: false,
managedHostname: '',
managedUrl: '',
managedUser: '',
pduMount: 'horizontal',
pduSide: 'right',
pduInputVoltage: '',
@@ -186,6 +190,10 @@ export const normalizeDiagram = (value: unknown): DiagramData => {
patchPanelPorts: clampNumber(item.patchPanelPorts, 0, 10000, libraryItem.type === 'patch-panel' ? 24 : 0),
patchPanelPortMap: normalizePatchPanelPorts(legacyItem.patchPanelPortMap, legacyItem.patchPanelPortIdentification),
networkPorts: normalizeNetworkPorts(legacyItem.networkPorts ?? legacyItem.switchPorts),
managed: Boolean(item.managed),
managedHostname: item.managedHostname || '',
managedUrl: item.managedUrl || '',
managedUser: item.managedUser || '',
pduMount,
pduSide: item.pduSide === 'left' ? 'left' : 'right',
pduInputVoltage: item.pduInputVoltage || '',