Files
shopdb/docs/archive/NETWORK_DEVICES_UNIFIED_DESIGN.md
cproudlock 94b421f73a Consolidate documentation: archive 45+ historical docs
- Move completed migration docs to docs/archive/
- Move session summaries to docs/archive/sessions/
- Rename API_ASP_DOCUMENTATION.md to docs/API.md
- Archive redundant Claude reference files
- Update docs/README.md as simplified index
- Reduce active docs from 45+ files to 8 essential files

Remaining docs:
- CLAUDE.md (AI context)
- TODO.md (task tracking)
- docs/README.md, API.md, QUICK_REFERENCE.md
- docs/ASP_DEVELOPMENT_GUIDE.md, STANDARDS.md

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-11 13:13:41 -05:00

25 KiB

Network Devices - Unified Page Design

Date: 2025-10-23 Approach: Single "Network Devices" page showing all infrastructure with filtering Files Required: 4 files total


Concept: One Page to Rule Them All

Instead of separate pages per device type, create a unified Network Devices page that shows:

  • Servers
  • Switches
  • 📹 Cameras
  • Access Points (if you add them later)
  • IDFs (Intermediate Distribution Frames)

User Experience:

  • Click "Network Devices" → See ALL devices in one table
  • Filter by type using tabs/dropdown
  • Click any device → Detail page (works for all types)
  • "Add Device" button → Select type, then add

Page Architecture

Main Pages (4 files)

network_devices.asp                           → List all devices with type filter
network_device_detail.asp?type=server&id=5   → View/edit any device
add_network_device.asp?type=server           → Add new device (any type)
save_network_device.asp                       → Universal save endpoint

Navigation

Main Menu:
  └─ Network Devices  (single menu item)
       └─ Opens network_devices.asp with tabs for filtering

File 1: network_devices.asp (Main List View)

Features

  • Tabs/Filter: All | Servers | Switches | Cameras | Access Points | IDFs
  • Unified Table: Shows all device types in one view
  • Device Type Badge: Visual indicator (Server, Switch, Camera, etc.)
  • Search: Filter by vendor, model, IP, serial number
  • Actions: View/Edit/Delete per device

UI Mockup

┌─────────────────────────────────────────────────────────────┐
│  Network Devices                        [+ Add Device]       │
├─────────────────────────────────────────────────────────────┤
│  [ All ] [ Servers ] [ Switches ] [ Cameras ] [ More ▼ ]   │
├─────────────────────────────────────────────────────────────┤
│ Type      | Vendor    | Model        | Serial | IP          │
├─────────────────────────────────────────────────────────────┤
│ [Server]  | Dell      | PowerEdge    | ABC123 | 10.0.1.5    │
│ [Switch]  | Cisco     | Catalyst 2960| XYZ789 | 10.0.1.1    │
│ [Camera]  | Hikvision | DS-2CD2142FWD| CAM001 | 10.0.2.10   │
│ [Server]  | HP        | ProLiant     | SRV456 | 10.0.1.6    │
└─────────────────────────────────────────────────────────────┘

Code Structure

<%
' Get filter parameter (default = all)
Dim filterType
filterType = Request.QueryString("filter")
If filterType = "" Then filterType = "all"

' Build query using vw_network_devices view
Dim strSQL
If filterType = "all" Then
    strSQL = "SELECT * FROM vw_network_devices WHERE isactive = 1 ORDER BY device_type, device_id DESC"
Else
    ' Filter by specific type (server, switch, camera)
    strSQL = "SELECT * FROM vw_network_devices WHERE device_type = '" & filterType & "' AND isactive = 1 ORDER BY device_id DESC"
End If

Set rs = objConn.Execute(strSQL)
%>

<!-- Tabs -->
<ul class="nav nav-tabs">
    <li class="nav-item">
        <a class="nav-link <%If filterType="all" Then Response.Write("active")%>"
           href="network_devices.asp?filter=all">All Devices</a>
    </li>
    <li class="nav-item">
        <a class="nav-link <%If filterType="Server" Then Response.Write("active")%>"
           href="network_devices.asp?filter=Server">Servers</a>
    </li>
    <li class="nav-item">
        <a class="nav-link <%If filterType="Switch" Then Response.Write("active")%>"
           href="network_devices.asp?filter=Switch">Switches</a>
    </li>
    <li class="nav-item">
        <a class="nav-link <%If filterType="Camera" Then Response.Write("active")%>"
           href="network_devices.asp?filter=Camera">Cameras</a>
    </li>
</ul>

<!-- Table -->
<table class="table table-hover">
    <thead>
        <tr>
            <th>Type</th>
            <th>Vendor</th>
            <th>Model</th>
            <th>Serial Number</th>
            <th>IP Address</th>
            <th>Description</th>
            <th>Actions</th>
        </tr>
    </thead>
    <tbody>
    <% Do While Not rs.EOF %>
        <tr>
            <td>
                <%
                ' Device type badge with icon
                Dim badgeClass, iconClass
                Select Case rs("device_type")
                    Case "Server"
                        badgeClass = "badge-primary"
                        iconClass = "zmdi-storage"
                    Case "Switch"
                        badgeClass = "badge-success"
                        iconClass = "zmdi-device-hub"
                    Case "Camera"
                        badgeClass = "badge-info"
                        iconClass = "zmdi-videocam"
                End Select
                %>
                <span class="badge <%=badgeClass%>">
                    <i class="zmdi <%=iconClass%>"></i> <%=rs("device_type")%>
                </span>
            </td>
            <td><%=Server.HTMLEncode(rs("vendor") & "")%></td>
            <td><%=Server.HTMLEncode(rs("modelnumber") & "")%></td>
            <td><%=Server.HTMLEncode(rs("serialnumber") & "")%></td>
            <td><%=Server.HTMLEncode(rs("ipaddress") & "")%></td>
            <td><%=Server.HTMLEncode(rs("description") & "")%></td>
            <td>
                <a href="network_device_detail.asp?type=<%=LCase(rs("device_type"))%>&id=<%=rs("device_id")%>">
                    <i class="zmdi zmdi-edit"></i> View
                </a>
            </td>
        </tr>
    <%
        rs.MoveNext
    Loop
    %>
    </tbody>
</table>

File 2: network_device_detail.asp (Detail/Edit View)

Features

  • Shows device details with vendor/model
  • Inline edit form (click Edit button)
  • Works for ANY device type
  • Map coordinates (if provided)
  • Link back to network_devices.asp

Code Structure

<%
' Get type and ID from URL
Dim deviceType, deviceId
deviceType = Request.QueryString("type")  ' server, switch, camera
deviceId = Request.QueryString("id")

' Validate type
If deviceType <> "server" AND deviceType <> "switch" AND deviceType <> "camera" Then
    Response.Redirect("network_devices.asp")
    Response.End
End If

' Map type to table/field names
Dim tableName, idField, displayName
Select Case deviceType
    Case "server"
        tableName = "servers"
        idField = "serverid"
        displayName = "Server"
    Case "switch"
        tableName = "switches"
        idField = "switchid"
        displayName = "Switch"
    Case "camera"
        tableName = "cameras"
        idField = "cameraid"
        displayName = "Camera"
End Select

' Fetch device with model/vendor
strSQL = "SELECT d.*, m.modelnumber, m.modelnumberid, v.vendor, v.vendorid " & _
         "FROM " & tableName & " d " & _
         "LEFT JOIN models m ON d.modelid = m.modelnumberid " & _
         "LEFT JOIN vendors v ON m.vendorid = v.vendorid " & _
         "WHERE d." & idField & " = " & deviceId

Set rs = objConn.Execute(strSQL)

If rs.EOF Then
    Response.Write("Device not found")
    Response.End
End If
%>

<div class="content-wrapper">
    <a href="network_devices.asp" class="btn btn-secondary">
        <i class="zmdi zmdi-arrow-left"></i> Back to Network Devices
    </a>

    <h2><%=displayName%> #<%=deviceId%></h2>

    <!-- Display Mode -->
    <div id="displayMode">
        <table class="table table-bordered">
            <tr>
                <th>Vendor</th>
                <td><%=Server.HTMLEncode(rs("vendor") & "N/A")%></td>
            </tr>
            <tr>
                <th>Model</th>
                <td><%=Server.HTMLEncode(rs("modelnumber") & "N/A")%></td>
            </tr>
            <tr>
                <th>Serial Number</th>
                <td><%=Server.HTMLEncode(rs("serialnumber") & "")%></td>
            </tr>
            <tr>
                <th>IP Address</th>
                <td><%=Server.HTMLEncode(rs("ipaddress") & "")%></td>
            </tr>
            <tr>
                <th>Description</th>
                <td><%=Server.HTMLEncode(rs("description") & "")%></td>
            </tr>
            <tr>
                <th>Map Position</th>
                <td>
                    <% If Not IsNull(rs("maptop")) And Not IsNull(rs("mapleft")) Then %>
                        Top: <%=rs("maptop")%>, Left: <%=rs("mapleft")%>
                        <a href="network_map.asp?highlight=<%=deviceType%>_<%=deviceId%>" target="_blank">
                            <i class="zmdi zmdi-map"></i> View on Map
                        </a>
                    <% Else %>
                        Not mapped
                    <% End If %>
                </td>
            </tr>
        </table>

        <button class="btn btn-primary" onclick="showEditMode()">
            <i class="zmdi zmdi-edit"></i> Edit <%=displayName%>
        </button>
    </div>

    <!-- Edit Mode (hidden by default) -->
    <div id="editMode" style="display:none;">
        <form method="post" action="save_network_device.asp">
            <input type="hidden" name="type" value="<%=deviceType%>">
            <input type="hidden" name="id" value="<%=deviceId%>">

            <div class="form-group">
                <label>Model</label>
                <select name="modelid" class="form-control">
                    <option value="">-- No Model --</option>
                    <%
                    Dim strSQL2, rsModels
                    strSQL2 = "SELECT m.modelnumberid, m.modelnumber, v.vendor " & _
                              "FROM models m " & _
                              "INNER JOIN vendors v ON m.vendorid = v.vendorid " & _
                              "WHERE m.isactive = 1 " & _
                              "ORDER BY v.vendor, m.modelnumber"
                    Set rsModels = objConn.Execute(strSQL2)
                    Do While Not rsModels.EOF
                        Dim selected
                        If Not IsNull(rs("modelnumberid")) Then
                            If rsModels("modelnumberid") = rs("modelnumberid") Then
                                selected = "selected"
                            Else
                                selected = ""
                            End If
                        End If
                    %>
                        <option value="<%=rsModels("modelnumberid")%>" <%=selected%>>
                            <%=Server.HTMLEncode(rsModels("vendor") & " - " & rsModels("modelnumber"))%>
                        </option>
                    <%
                        rsModels.MoveNext
                    Loop
                    rsModels.Close
                    Set rsModels = Nothing
                    %>
                </select>
            </div>

            <div class="form-group">
                <label>Serial Number</label>
                <input type="text" name="serialnumber" class="form-control"
                       value="<%=Server.HTMLEncode(rs("serialnumber") & "")%>" maxlength="100">
            </div>

            <div class="form-group">
                <label>IP Address</label>
                <input type="text" name="ipaddress" class="form-control"
                       value="<%=Server.HTMLEncode(rs("ipaddress") & "")%>"
                       maxlength="15" pattern="^[0-9\.]+$">
            </div>

            <div class="form-group">
                <label>Description</label>
                <textarea name="description" class="form-control" rows="3"><%=Server.HTMLEncode(rs("description") & "")%></textarea>
            </div>

            <div class="form-group">
                <label>Map Position (Optional)</label>
                <div class="row">
                    <div class="col-md-6">
                        <input type="number" name="maptop" class="form-control"
                               placeholder="Top (Y)" value="<%=rs("maptop") & ""%>">
                    </div>
                    <div class="col-md-6">
                        <input type="number" name="mapleft" class="form-control"
                               placeholder="Left (X)" value="<%=rs("mapleft") & ""%>">
                    </div>
                </div>
            </div>

            <button type="submit" class="btn btn-success">
                <i class="zmdi zmdi-save"></i> Save Changes
            </button>
            <button type="button" class="btn btn-secondary" onclick="showDisplayMode()">
                Cancel
            </button>
        </form>
    </div>
</div>

<script>
function showEditMode() {
    document.getElementById('displayMode').style.display = 'none';
    document.getElementById('editMode').style.display = 'block';
}
function showDisplayMode() {
    document.getElementById('displayMode').style.display = 'block';
    document.getElementById('editMode').style.display = 'none';
}
</script>

File 3: add_network_device.asp (Add Form)

Features

  • First: Select device type (Server, Switch, Camera, etc.)
  • Then: Show form with fields
  • Model/vendor dropdown
  • All standard fields
  • Optional map coordinates

Code Structure

<%
' Get device type (from URL or form)
Dim deviceType
deviceType = Request.QueryString("type")

' If no type selected, show type selector
If deviceType = "" OR (deviceType <> "server" AND deviceType <> "switch" AND deviceType <> "camera") Then
%>
    <div class="content-wrapper">
        <h2>Add Network Device</h2>
        <p>Select the type of device you want to add:</p>

        <div class="row">
            <div class="col-md-4">
                <div class="card text-center">
                    <div class="card-body">
                        <i class="zmdi zmdi-storage" style="font-size:48px;"></i>
                        <h5>Server</h5>
                        <a href="add_network_device.asp?type=server" class="btn btn-primary">
                            Add Server
                        </a>
                    </div>
                </div>
            </div>

            <div class="col-md-4">
                <div class="card text-center">
                    <div class="card-body">
                        <i class="zmdi zmdi-device-hub" style="font-size:48px;"></i>
                        <h5>Switch</h5>
                        <a href="add_network_device.asp?type=switch" class="btn btn-success">
                            Add Switch
                        </a>
                    </div>
                </div>
            </div>

            <div class="col-md-4">
                <div class="card text-center">
                    <div class="card-body">
                        <i class="zmdi zmdi-videocam" style="font-size:48px;"></i>
                        <h5>Camera</h5>
                        <a href="add_network_device.asp?type=camera" class="btn btn-info">
                            Add Camera
                        </a>
                    </div>
                </div>
            </div>
        </div>

        <a href="network_devices.asp" class="btn btn-secondary">Cancel</a>
    </div>
<%
    Response.End
End If

' Type is selected, show form
Dim displayName
Select Case deviceType
    Case "server": displayName = "Server"
    Case "switch": displayName = "Switch"
    Case "camera": displayName = "Camera"
End Select
%>

<div class="content-wrapper">
    <h2>Add <%=displayName%></h2>

    <form method="post" action="save_network_device.asp">
        <input type="hidden" name="type" value="<%=deviceType%>">

        <div class="form-group">
            <label>Model <span class="text-danger">*</span></label>
            <select name="modelid" required class="form-control">
                <option value="">-- Select Model --</option>
                <%
                strSQL = "SELECT m.modelnumberid, m.modelnumber, v.vendor " & _
                         "FROM models m " & _
                         "INNER JOIN vendors v ON m.vendorid = v.vendorid " & _
                         "WHERE m.isactive = 1 " & _
                         "ORDER BY v.vendor, m.modelnumber"
                Set rsModels = objConn.Execute(strSQL)
                Do While Not rsModels.EOF
                %>
                    <option value="<%=rsModels("modelnumberid")%>">
                        <%=Server.HTMLEncode(rsModels("vendor") & " - " & rsModels("modelnumber"))%>
                    </option>
                <%
                    rsModels.MoveNext
                Loop
                rsModels.Close
                Set rsModels = Nothing
                %>
            </select>
            <small class="form-text text-muted">
                Don't see your model? <a href="addmodel.asp" target="_blank">Add a new model first</a>
            </small>
        </div>

        <div class="form-group">
            <label>Serial Number</label>
            <input type="text" name="serialnumber" class="form-control" maxlength="100">
        </div>

        <div class="form-group">
            <label>IP Address</label>
            <input type="text" name="ipaddress" class="form-control"
                   maxlength="15" pattern="^[0-9\.]+$" placeholder="192.168.1.100">
        </div>

        <div class="form-group">
            <label>Description</label>
            <textarea name="description" class="form-control" rows="3"
                      placeholder="Location, purpose, notes..."></textarea>
        </div>

        <div class="form-group">
            <label>Map Position (Optional)</label>
            <div class="row">
                <div class="col-md-6">
                    <input type="number" name="maptop" class="form-control"
                           placeholder="Top (Y coordinate)">
                </div>
                <div class="col-md-6">
                    <input type="number" name="mapleft" class="form-control"
                           placeholder="Left (X coordinate)">
                </div>
            </div>
            <small class="form-text text-muted">
                Used for network map visualization. Leave blank if unknown.
            </small>
        </div>

        <button type="submit" class="btn btn-success">
            <i class="zmdi zmdi-save"></i> Add <%=displayName%>
        </button>
        <a href="network_devices.asp" class="btn btn-secondary">Cancel</a>
    </form>
</div>

File 4: save_network_device.asp (Universal Save)

Features

  • Handles INSERT and UPDATE for all device types
  • Validates all inputs
  • Redirects back to appropriate page

Code Structure

<!--#include file="./includes/sql.asp"-->
<!--#include file="./includes/error_handler.asp"-->
<!--#include file="./includes/validation.asp"-->
<!--#include file="./includes/db_helpers.asp"-->

<%
' Get device type
Dim deviceType
deviceType = Request.Form("type")

' Validate type
If deviceType <> "server" AND deviceType <> "switch" AND deviceType <> "camera" Then
    Response.Write("Error: Invalid device type")
    Response.End
End If

' Map to table/field names
Dim tableName, idField
Select Case deviceType
    Case "server"
        tableName = "servers"
        idField = "serverid"
    Case "switch"
        tableName = "switches"
        idField = "switchid"
    Case "camera"
        tableName = "cameras"
        idField = "cameraid"
End Select

' Get and validate form data
Dim deviceId, modelid, serialnumber, ipaddress, description, maptop, mapleft

deviceId = GetSafeInteger("FORM", "id", 0, 0, 999999)
modelid = GetSafeInteger("FORM", "modelid", 0, 0, 999999)
serialnumber = GetSafeString("FORM", "serialnumber", "", 0, 100, "^[A-Za-z0-9\-\s]*$")
ipaddress = GetSafeString("FORM", "ipaddress", "", 0, 15, "^[0-9\.]*$")
description = GetSafeString("FORM", "description", "", 0, 255, "")
maptop = GetSafeInteger("FORM", "maptop", 0, 0, 999999)
mapleft = GetSafeInteger("FORM", "mapleft", 0, 0, 999999)

' Convert 0 to NULL for optional fields
If modelid = 0 Then modelid = Null
If maptop = 0 Then maptop = Null
If mapleft = 0 Then mapleft = Null

' Validate required fields
If IsNull(modelid) Then
    Response.Write("Error: Model is required")
    Response.End
End If

' Build query
Dim strSQL

If deviceId = 0 Then
    ' INSERT - New device
    strSQL = "INSERT INTO " & tableName & " " & _
             "(modelid, serialnumber, ipaddress, description, maptop, mapleft, isactive) " & _
             "VALUES (?, ?, ?, ?, ?, ?, 1)"

    Set rs = ExecuteParameterizedQuery(objConn, strSQL, _
        Array(modelid, serialnumber, ipaddress, description, maptop, mapleft))

    ' Get new ID for redirect
    deviceId = objConn.Execute("SELECT LAST_INSERT_ID() as newid")(0)
Else
    ' UPDATE - Existing device
    strSQL = "UPDATE " & tableName & " " & _
             "SET modelid = ?, serialnumber = ?, ipaddress = ?, description = ?, " & _
             "    maptop = ?, mapleft = ? " & _
             "WHERE " & idField & " = ?"

    Set rs = ExecuteParameterizedQuery(objConn, strSQL, _
        Array(modelid, serialnumber, ipaddress, description, maptop, mapleft, deviceId))
End If

Call CleanupResources()

' Redirect to detail page
Response.Redirect("network_device_detail.asp?type=" & deviceType & "&id=" & deviceId)
%>

Navigation Update

leftsidebar.asp

<!-- Network Section -->
<li class="nav-header">NETWORK</li>
<li>
    <a href="network_devices.asp">
        <i class="zmdi zmdi-devices"></i> Network Devices
    </a>
</li>
<li>
    <a href="network_map.asp">
        <i class="zmdi zmdi-map"></i> Network Map
    </a>
</li>
<li>
    <a href="displaysubnets.asp">
        <i class="zmdi zmdi-network"></i> Subnets
    </a>
</li>

Database View: vw_network_devices

The migration script already creates this! It unifies all infrastructure:

CREATE VIEW vw_network_devices AS
SELECT
  'Server' AS device_type,
  serverid AS device_id,
  modelid, modelnumber, vendor,
  serialnumber, ipaddress, description,
  maptop, mapleft, isactive
FROM servers
LEFT JOIN models ON servers.modelid = models.modelnumberid
LEFT JOIN vendors ON models.vendorid = vendors.vendorid

UNION ALL

SELECT
  'Switch' AS device_type,
  switchid AS device_id,
  modelid, modelnumber, vendor,
  serialnumber, ipaddress, description,
  maptop, mapleft, isactive
FROM switches
LEFT JOIN models ON switches.modelid = models.modelnumberid
LEFT JOIN vendors ON models.vendorid = vendors.vendorid

UNION ALL

SELECT
  'Camera' AS device_type,
  cameraid AS device_id,
  modelid, modelnumber, vendor,
  serialnumber, ipaddress, description,
  maptop, mapleft, isactive
FROM cameras
LEFT JOIN models ON cameras.modelid = models.modelnumberid
LEFT JOIN vendors ON models.vendorid = vendors.vendorid

Future: Adding More Device Types

To add Access Points or IDFs later:

  1. Database:

    CREATE TABLE accesspoints (
        accesspointid INT(11) PRIMARY KEY AUTO_INCREMENT,
        modelid INT(11),
        serialnumber VARCHAR(100),
        ipaddress VARCHAR(15),
        description VARCHAR(255),
        maptop INT(11),
        mapleft INT(11),
        isactive BIT(1) DEFAULT b'1',
        FOREIGN KEY (modelid) REFERENCES models(modelnumberid)
    );
    
    -- Add to view
    ALTER VIEW vw_network_devices AS
    -- ... existing unions ...
    UNION ALL
    SELECT 'Access Point' AS device_type, accesspointid AS device_id, ...
    FROM accesspoints ...
    
  2. Code: Just add new case to Select statements!

    Case "accesspoint"
        tableName = "accesspoints"
        idField = "accesspointid"
        displayName = "Access Point"
    
  3. UI: Add new tab to network_devices.asp

That's it! The unified design makes it trivial to extend.


Summary: Why This Is Better

Single source of truth - One page for all infrastructure Easy filtering - Tabs to view by type or see all Consistent UX - Same interface for all device types Uses existing view - vw_network_devices already unifies them Only 4 files - vs 12 separate files Easy to extend - Add new device types without file duplication Matches mental model - "Network Devices" is how users think Search/filter across all - Find any device in one place


Ready to build? This is the cleanest approach!