Files
shopdb/displaylocations.asp
cproudlock 08ffa4ba36 Add displaylocations, location/inspection migrations, UI refinements
- New displaylocations.asp (production location listing)
- 3 new SQL migrations: inspection machine type, location relationship
  types, pctype inspection update
- displaymachine.asp / printbadge.asp substantial rework
- editmachine/editpc/savemachineedit: ~50 line additions each
- Dashboard index.html + tv-dashboard tweaks
- .gitignore: block database-backup-*.sql, *.bak, *.pdf

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 12:06:28 -04:00

354 lines
14 KiB
Plaintext

<%@ Language=VBScript %>
<%
Option Explicit
Dim theme, strSQL, rs, objConn, rsRel
%>
<!DOCTYPE html>
<html lang="en">
<head>
<!--#include file="./includes/header.asp"-->
<!--#include file="./includes/sql.asp"-->
</head>
<%
theme = Request.Cookies("theme")
IF theme = "" THEN
theme="bg-theme1"
END IF
%>
<body class="bg-theme <%Response.Write(theme)%>">
<!-- start loader -->
<div id="pageloader-overlay" class="visible incoming"><div class="loader-wrapper-outer"><div class="loader-wrapper-inner" ><div class="loader"></div></div></div></div>
<!-- end loader -->
<!-- Start wrapper-->
<div id="wrapper">
<!--#include file="./includes/leftsidebar.asp"-->
<!--Start topbar header-->
<!--#include file="./includes/topbarheader.asp"-->
<!--End topbar header-->
<div class="clearfix"></div>
<div class="content-wrapper">
<div class="container-fluid">
<div class="row">
<div class="col-xl-auto">
<div class="card">
<div class="card-body">
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:15px;">
<h5 class="card-title" style="margin:0;">
<i class="zmdi zmdi-pin"></i> Locations
</h5>
</div>
<%
' Get all active locations with PC counts and relationship counts
strSQL = "SELECT m.machineid, m.machinenumber, m.alias, m.machinenotes, m.mapleft, m.maptop, " & _
" (SELECT COUNT(*) FROM machinerelationships mr " & _
" JOIN machines pc ON mr.related_machineid = pc.machineid " & _
" WHERE mr.machineid = m.machineid AND mr.isactive = 1 AND pc.pctypeid IS NOT NULL AND pc.isactive = 1) AS pc_count, " & _
" (SELECT COUNT(*) FROM machinerelationships mr " & _
" JOIN machines child ON mr.related_machineid = child.machineid " & _
" WHERE mr.machineid = m.machineid AND mr.isactive = 1 AND child.islocationonly = 1 AND child.isactive = 1) AS sublocation_count " & _
"FROM machines m " & _
"WHERE m.islocationonly = 1 AND m.isactive = 1 AND m.machinenumber <> 'TBD' " & _
"ORDER BY m.machinenumber"
Set rs = objConn.Execute(strSQL)
' Build a dictionary of all relationships for location machines
' Key = machineid, Value = array of relationship info
Dim relDict, relSQL
Set relDict = Server.CreateObject("Scripting.Dictionary")
relSQL = "SELECT mr.machineid AS loc_id, child.machineid AS child_id, child.machinenumber AS child_name, " & _
" child.hostname AS child_hostname, child.alias AS child_alias, " & _
" child.pctypeid, child.islocationonly, " & _
" rt.relationshiptype, rt.relationshiptypeid, " & _
" GROUP_CONCAT(DISTINCT c.address ORDER BY c.address SEPARATOR ', ') AS child_ip " & _
"FROM machinerelationships mr " & _
"JOIN machines loc ON mr.machineid = loc.machineid " & _
"JOIN machines child ON mr.related_machineid = child.machineid " & _
"JOIN relationshiptypes rt ON mr.relationshiptypeid = rt.relationshiptypeid " & _
"LEFT JOIN communications c ON child.machineid = c.machineid AND c.comstypeid IN (1, 3) AND c.isactive = 1 " & _
"WHERE loc.islocationonly = 1 AND loc.isactive = 1 AND mr.isactive = 1 AND child.isactive = 1 " & _
"GROUP BY mr.machineid, child.machineid, child.machinenumber, child.hostname, child.alias, " & _
" child.pctypeid, child.islocationonly, rt.relationshiptype, rt.relationshiptypeid " & _
"ORDER BY mr.machineid, rt.relationshiptypeid, child.machinenumber"
Set rsRel = objConn.Execute(relSQL)
Dim curLocId
Do While Not rsRel.EOF
curLocId = CStr(rsRel("loc_id"))
If Not relDict.Exists(curLocId) Then
relDict.Add curLocId, ""
End If
' Build pipe-delimited entries: child_id|child_name|child_hostname|child_alias|child_ip|pctypeid|islocationonly|relationshiptype
Dim entry
entry = rsRel("child_id") & "|" & (rsRel("child_name") & "") & "|" & (rsRel("child_hostname") & "") & "|" & _
(rsRel("child_alias") & "") & "|" & (rsRel("child_ip") & "") & "|" & _
(rsRel("pctypeid") & "") & "|" & (rsRel("islocationonly") & "") & "|" & (rsRel("relationshiptype") & "")
If relDict(curLocId) <> "" Then
relDict(curLocId) = relDict(curLocId) & "~" & entry
Else
relDict(curLocId) = entry
End If
rsRel.MoveNext
Loop
rsRel.Close
Set rsRel = Nothing
%>
<div class="table-responsive">
<table id="locationsTable" class="table table-striped table-hover">
<thead>
<tr>
<th></th>
<th>Location</th>
<th>Alias</th>
<th>PCs</th>
<th>Sub-locations</th>
<th>Map</th>
<th>Notes</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<%
Do While Not rs.EOF
Dim locName, locAlias, locNotes, pcCount, subCount, hasMap, mid, totalRels
mid = rs("machineid")
locName = rs("machinenumber") & ""
locAlias = rs("alias") & ""
locNotes = rs("machinenotes") & ""
pcCount = CLng(rs("pc_count") & "")
subCount = CLng(rs("sublocation_count") & "")
hasMap = Not (IsNull(rs("mapleft")) Or IsNull(rs("maptop")))
totalRels = pcCount + subCount
' Check if this location has any relationships in our dict
Dim hasRels, midStr
midStr = CStr(mid)
hasRels = relDict.Exists(midStr) And relDict(midStr) <> ""
%>
<tr<% If hasRels Then %> class="loc-parent" data-mid="<%=mid%>" style="cursor:pointer;"<% End If %>>
<td style="width:30px;">
<% If hasRels Then %>
<i class="zmdi zmdi-chevron-right loc-toggle" data-mid="<%=mid%>" style="transition:transform 0.2s;"></i>
<% End If %>
</td>
<td>
<a href="displaymachine.asp?machineid=<%=mid%>">
<i class="zmdi zmdi-pin" style="margin-right:5px;"></i><%=Server.HTMLEncode(locName)%>
</a>
</td>
<td><%=Server.HTMLEncode(locAlias)%></td>
<td>
<% If pcCount > 0 Then %>
<span class="badge badge-primary"><%=pcCount%></span>
<% Else %>
<span class="text-muted">0</span>
<% End If %>
</td>
<td>
<% If subCount > 0 Then %>
<span class="badge badge-info"><%=subCount%></span>
<% Else %>
<span class="text-muted">0</span>
<% End If %>
</td>
<td>
<% If hasMap Then %>
<i class="zmdi zmdi-pin text-success" title="Location set"></i>
<% Else %>
<i class="zmdi zmdi-pin-off text-muted" title="No location set"></i>
<% End If %>
</td>
<td><span title="<%=Server.HTMLEncode(locNotes)%>"><%
If Len(locNotes) > 40 Then
Response.Write(Server.HTMLEncode(Left(locNotes, 40)) & "...")
Else
Response.Write(Server.HTMLEncode(locNotes))
End If
%></span></td>
<td>
<a href="displaymachine.asp?machineid=<%=mid%>" class="btn btn-sm btn-outline-info" title="View">
<i class="zmdi zmdi-eye"></i>
</a>
<a href="printbadge.asp?machineid=<%=mid%>" class="btn btn-sm btn-outline-secondary" title="Print Label" target="_blank">
<i class="zmdi zmdi-label"></i>
</a>
</td>
</tr>
<%
' Render hidden detail rows for this location's relationships
If hasRels Then
Dim entries, i, parts
entries = Split(relDict(midStr), "~")
For i = 0 To UBound(entries)
parts = Split(entries(i), "|")
' parts: 0=child_id, 1=child_name, 2=child_hostname, 3=child_alias, 4=child_ip, 5=pctypeid, 6=islocationonly, 7=relationshiptype
Dim cId, cName, cHost, cAlias, cIp, cIsPC, cIsLoc, cRelType, cBadgeClass, cIcon, cLink
cId = parts(0)
cName = parts(1)
cHost = parts(2)
cAlias = parts(3)
cIp = parts(4)
cIsPC = (parts(5) <> "")
cIsLoc = (parts(6) = "1" Or parts(6) = "True")
cRelType = parts(7)
' Determine icon and badge
If cIsLoc Then
cIcon = "zmdi zmdi-pin text-info"
cBadgeClass = "badge-info"
cLink = "displaymachine.asp?machineid=" & cId
ElseIf cIsPC Then
cIcon = "zmdi zmdi-desktop-windows text-primary"
cBadgeClass = "badge-primary"
cLink = "displaypc.asp?machineid=" & cId
Else
cIcon = "zmdi zmdi-memory text-warning"
cBadgeClass = "badge-warning"
cLink = "displaymachine.asp?machineid=" & cId
End If
' Display name: use hostname for PCs if available, else machinenumber
Dim displayName
If cIsPC And cHost <> "" Then
displayName = cHost
Else
displayName = cName
End If
%>
<tr class="loc-detail loc-detail-<%=mid%>" style="display:none;">
<td></td>
<td style="padding-left:30px;">
<i class="<%=cIcon%>" style="margin-right:5px;"></i>
<a href="<%=cLink%>"><%=Server.HTMLEncode(displayName)%></a>
<% If cAlias <> "" Then %>
<small class="text-muted"> (<%=Server.HTMLEncode(cAlias)%>)</small>
<% End If %>
</td>
<td>
<% If cIp <> "" Then %>
<small><%=Server.HTMLEncode(cIp)%></small>
<% End If %>
</td>
<td colspan="2">
<span class="badge <%=cBadgeClass%>"><%=Server.HTMLEncode(cRelType)%></span>
</td>
<td></td>
<td></td>
<td>
<a href="<%=cLink%>" class="btn btn-sm btn-outline-info" title="View">
<i class="zmdi zmdi-eye"></i>
</a>
</td>
</tr>
<%
Next
End If
rs.MoveNext
Loop
rs.Close
Set rs = Nothing
Set relDict = Nothing
%>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div><!--End content-wrapper-->
<!--Start Back To Top Button-->
<a href="javaScript:void();" class="back-to-top"><i class="fa fa-angle-double-up"></i> </a>
<!--End Back To Top Button-->
<!--Start footer-->
<footer class="footer">
<div class="container">
<div class="text-center">
</div>
</div>
</footer>
<!--End footer-->
</div><!--End wrapper-->
<!-- Bootstrap core JavaScript-->
<script src="assets/js/jquery.min.js"></script>
<script src="assets/js/popper.min.js"></script>
<script src="assets/js/bootstrap.min.js"></script>
<!-- simplebar js -->
<script src="assets/plugins/simplebar/js/simplebar.js"></script>
<!-- sidebar-menu js -->
<script src="assets/js/sidebar-menu.js"></script>
<!-- DataTables -->
<link rel="stylesheet" href="assets/plugins/datatables/dataTables.bootstrap4.min.css">
<script src="assets/plugins/datatables/jquery.dataTables.min.js"></script>
<script src="assets/plugins/datatables/dataTables.bootstrap4.min.js"></script>
<!-- Custom scripts -->
<script src="assets/js/app-script.js"></script>
<style>
.loc-detail td {
border-top: none !important;
padding-top: 2px !important;
padding-bottom: 2px !important;
background: rgba(0,0,0,0.05) !important;
}
.loc-toggle.open {
transform: rotate(90deg);
}
.loc-parent:hover {
background: rgba(255,255,255,0.03);
}
</style>
<script>
$(document).ready(function() {
var dt = $('#locationsTable').DataTable({
"order": [[1, "asc"]],
"pageLength": 25,
"language": {
"emptyTable": "No locations found",
"search": "Filter:"
},
"columnDefs": [
{ "orderable": false, "targets": 0 },
{ "searchable": false, "targets": 0 }
]
});
// Toggle detail rows
$('#locationsTable').on('click', '.loc-parent', function(e) {
// Don't toggle if clicking a link or button
if ($(e.target).closest('a, button').length) return;
var mid = $(this).data('mid');
var toggle = $(this).find('.loc-toggle');
var details = $('.loc-detail-' + mid);
if (details.first().is(':visible')) {
details.hide();
toggle.removeClass('open');
} else {
details.show();
toggle.addClass('open');
}
});
});
</script>
</body>
</html>
<%
objConn.Close
%>