diff --git a/README.md b/README.md
index e028d51..0d77e6e 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/src/App.tsx b/src/App.tsx
index d8a3741..3d90e14 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -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({
>
)}
+ {PORT_MAPPED_COMPONENTS.has(selectedEquipment.type) && (
+ <>
+
+
+ Managed Device
+
+
+
+ Managed
+
+
+ onEquipmentChange(selectedEquipmentRack.id, selectedEquipment.id, {
+ managed: (value as number) === 1,
+ })
+ }
+ />
+
+ {selectedEquipment.managed && (
+ <>
+
+ onEquipmentChange(selectedEquipmentRack.id, selectedEquipment.id, {
+ managedHostname: event.target.value,
+ })
+ }
+ fullWidth
+ />
+
+ onEquipmentChange(selectedEquipmentRack.id, selectedEquipment.id, {
+ managedUrl: event.target.value,
+ })
+ }
+ fullWidth
+ />
+
+ onEquipmentChange(selectedEquipmentRack.id, selectedEquipment.id, {
+ managedUser: event.target.value,
+ })
+ }
+ fullWidth
+ />
+ >
+ )}
+ >
+ )}
{selectedEquipment.type === 'pdu' && (
<>
diff --git a/src/types.ts b/src/types.ts
index 9cf4fb1..728ed09 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -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;
diff --git a/src/utils/model.ts b/src/utils/model.ts
index e0b1c6b..e0612cf 100644
--- a/src/utils/model.ts
+++ b/src/utils/model.ts
@@ -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 || '',