Fix network device description/machinenotes display and edit

- Fix ADO cursor issue where reading rs("description") twice caused
  empty values (IsNull check consumed the field value)
- Change all device pages to read description field once using
  `description = rs("description") & ""` pattern
- Add deviceDescription variable in displaydevice.asp
- Fix machinetypeid mapping: IDF=17, Camera=18 (was swapped)
- Add model dropdown fix to include currently assigned model
- Add server application tracking feature
- Various other improvements and fixes

Files affected:
- displaydevice.asp, displaylocationdevice.asp
- deviceaccesspoint.asp, deviceserver.asp, deviceswitch.asp
- devicecamera.asp, deviceidf.asp
- savenetworkdevice.asp, networkdevices.asp

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
cproudlock
2025-12-17 13:47:56 -05:00
parent a5b4013949
commit a4096ace94
25 changed files with 1744 additions and 355 deletions

View File

@@ -1,12 +1,17 @@
<%@ Language=VBScript %>
<%
Option Explicit
%>
<!--#include file="./includes/sql.asp"-->
<%
Dim appid, rs
Dim appid, rs, theme, kbClicks, kbDesc, kbClicksNum
Dim strSQL, installPath, docPath, appLink, teamUrl
Dim rsKB, sqlKB, appName, rsSupportTeams, sqlSupportTeams
Dim rsAppOwners, sqlAppOwners
appid = Request.Querystring("appid")
' Get highlight parameter for shared links
Dim highlightId
highlightId = Request.QueryString("highlight")
' Basic validation - must be numeric and positive
If Not IsNumeric(appid) Or CLng(appid) < 1 Then
Response.Redirect("displayapplications.asp")
@@ -15,14 +20,12 @@ Option Explicit
appid = CLng(appid) ' Convert to long integer
Dim theme
theme = Request.Cookies("theme")
IF theme = "" THEN
theme="bg-theme1"
END IF
' Simple query with validated integer
Dim strSQL
strSQL = "SELECT a.*, s.teamname, s.teamurl, o.appowner, o.sso " & _
"FROM applications a " & _
"INNER JOIN supportteams s ON a.supportteamid = s.supporteamid " & _
@@ -43,11 +46,80 @@ Option Explicit
<!--#include file="./includes/header.asp"-->
</head>
<style>
.highlighted-result {
background: linear-gradient(90deg, rgba(255, 193, 7, 0.3) 0%, rgba(255, 193, 7, 0.1) 100%) !important;
border-left: 4px solid #ffc107 !important;
animation: highlight-pulse 2s ease-in-out 3;
}
@keyframes highlight-pulse {
0%, 100% { background: linear-gradient(90deg, rgba(255, 193, 7, 0.3) 0%, rgba(255, 193, 7, 0.1) 100%); }
50% { background: linear-gradient(90deg, rgba(255, 193, 7, 0.5) 0%, rgba(255, 193, 7, 0.2) 100%); }
}
.card-img-block img {
cursor: pointer;
transition: opacity 0.2s;
}
.card-img-block img:hover {
opacity: 0.85;
}
.lightbox-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.85);
z-index: 9999;
justify-content: center;
align-items: center;
}
.lightbox-overlay.active {
display: flex;
}
.lightbox-content {
position: relative;
max-width: 90%;
max-height: 90%;
}
.lightbox-content img {
max-width: 100%;
max-height: 85vh;
border-radius: 8px;
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.5);
}
.lightbox-close {
position: absolute;
top: -40px;
right: -10px;
color: #fff;
font-size: 32px;
cursor: pointer;
opacity: 0.8;
transition: opacity 0.2s;
background: none;
border: none;
padding: 5px 10px;
}
.lightbox-close:hover {
opacity: 1;
}
</style>
<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 -->
<!-- Lightbox overlay -->
<div id="imageLightbox" class="lightbox-overlay" onclick="closeLightbox(event)">
<div class="lightbox-content" onclick="event.stopPropagation()">
<button class="lightbox-close" onclick="closeLightbox(event)">&times;</button>
<img src="./images/applications/<%=Server.HTMLEncode(rs("image") & "")%>" alt="<%=Server.HTMLEncode(rs("appname") & "")%>">
</div>
</div>
<!-- Start wrapper-->
<div id="wrapper">
<!--#include file="./includes/leftsidebar.asp"-->
@@ -63,7 +135,7 @@ Option Explicit
<div class="col-lg-4">
<div class="card profile-card-2">
<div class="card-img-block">
<img class="img-fluid" src="./images/applications/<%=Server.HTMLEncode(rs("image") & "")%>" alt="Card image cap">
<img class="img-fluid" src="./images/applications/<%=Server.HTMLEncode(rs("image") & "")%>" alt="<%=Server.HTMLEncode(rs("appname") & "")%>" onclick="openLightbox()" title="Click to enlarge">
</div>
<div class="card-body pt-5">
<img src="./images/applications/<%=Server.HTMLEncode(rs("image") & "")%>" alt="profile-image" class="profile">
@@ -90,13 +162,19 @@ Option Explicit
<div class="tab-content p-3">
<div class="tab-pane active" id="profile">
<h5 class="mb-3"><%=Server.HTMLEncode(rs("appname") & "")%></h5>
<%
Dim appDescription
appDescription = rs("appdescription") & ""
If appDescription <> "" Then
Response.Write("<p class='mb-3'>" & Server.HTMLEncode(appDescription) & "</p>")
End If
%>
<div class="row">
<div class="col-md-3">
<p class="mb-2"><strong>Support Team:</strong></p>
<p class="mb-2"><strong>App Owner:</strong></p>
<p class="mb-2"><strong>SSO:</strong></p>
<%
Dim installPath, docPath, appLink
installPath = rs("installpath") & ""
appLink = rs("applicationlink") & ""
docPath = rs("documentationpath") & ""
@@ -113,7 +191,6 @@ Option Explicit
</div>
<div class="col-md-8">
<%
Dim teamUrl
teamUrl = rs("teamurl") & ""
If teamUrl <> "" Then
Response.Write("<p class='mb-2'><a href='" & Server.HTMLEncode(teamUrl) & "' target='_blank' title='Click here for Service Now page'>" & Server.HTMLEncode(rs("teamname")) & "</a></p>")
@@ -137,43 +214,30 @@ Option Explicit
</div>
<div class="col-md-12">
<h5 class="mt-2 mb-3">Application Notes</h5>
<div class="table-responsive">
<table class="table table-hover table-striped">
<tbody>
<tr>
<td>
<strong><%Response.Write(rs("appname"))%></strong>:
</td>
</tr>
<tr>
<td><%Response.Write(rs("applicationnotes"))%>
</td>
</tr>
</tbody>
</table>
</div>
<div class="table-responsive">
<table class="table table-hover table-striped" style="font-size: 1rem;">
<tbody>
<tr>
<td style="padding: 12px;">
<strong><%=Server.HTMLEncode(rs("appname") & "")%></strong>:
</td>
</tr>
<tr>
<td style="padding: 12px;"><%=rs("applicationnotes") & ""%></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-md-12">
<h5 class="mt-4 mb-3"><i class="zmdi zmdi-collection-bookmark"></i> Related Knowledge Base Articles</h5>
<%
' Query knowledge base articles for this application
' Use keyword matching similar to search.asp - match on app name in keywords/description
Dim rsKB, sqlKB, appName
appName = rs("appname") & ""
' Search for articles where keywords or shortdescription contain the app name
' Also include articles explicitly linked via appid
' Sort by clicks (highest first), then prioritize directly linked articles
sqlKB = "SELECT linkid, linkurl, shortdescription, COALESCE(clicks, 0) as clicks, " & _
"CASE WHEN appid = " & appid & " THEN 1 ELSE 0 END as direct_link, " & _
"CAST(COALESCE(clicks, 0) AS SIGNED) as clicks_num " & _
' Query knowledge base articles directly linked to this application
sqlKB = "SELECT linkid, linkurl, shortdescription, COALESCE(clicks, 0) as clicks " & _
"FROM knowledgebase " & _
"WHERE isactive = 1 " & _
"AND (appid = " & appid & " " & _
" OR keywords LIKE '%" & Replace(appName, "'", "''") & "%' " & _
" OR shortdescription LIKE '%" & Replace(appName, "'", "''") & "%') " & _
"ORDER BY clicks_num DESC, direct_link DESC"
"WHERE isactive = 1 AND appid = " & appid & " " & _
"ORDER BY clicks DESC"
Set rsKB = objConn.Execute(sqlKB)
If Not rsKB.EOF Then
@@ -183,16 +247,12 @@ Option Explicit
<thead>
<tr>
<th style="padding: 12px;">Article</th>
<th style="width:100px; text-align:center; padding: 12px;">
<i class="zmdi zmdi-eye"></i> Clicks
</th>
<th style="width:100px; text-align:center; padding: 12px;">Clicks</th>
<th style="width:60px; text-align:center; padding: 12px;">Share</th>
</tr>
</thead>
<tbody>
<%
' Declare loop variables once outside the loop
Dim kbClicks, kbDesc, kbClicksNum
While Not rsKB.EOF
' Get click count with proper error handling
On Error Resume Next
@@ -214,14 +274,22 @@ Option Explicit
kbDesc = "[No description]"
End If
On Error Goto 0
' Check if this row should be highlighted
Dim rowClass, kbLinkId
kbLinkId = rsKB("linkid")
rowClass = ""
If highlightId <> "" And CStr(kbLinkId) = CStr(highlightId) Then
rowClass = " class='highlighted-result'"
End If
%>
<tr>
<tr id="kb-<%=Server.HTMLEncode(kbLinkId)%>"<%=rowClass%>>
<td style="padding: 12px;">
<a href="./clickcounter.asp?linkid=<%=Server.HTMLEncode(rsKB("linkid"))%>"
<a href="./clickcounter.asp?linkid=<%=Server.HTMLEncode(kbLinkId)%>"
target="_blank"
title="<%=Server.HTMLEncode(kbDesc)%>"
style="font-size: 1rem;">
<i class="zmdi zmdi-link" style="font-size: 1.1rem;"></i> <%=Server.HTMLEncode(kbDesc)%>
<%=Server.HTMLEncode(kbDesc)%>
</a>
</td>
<td style="text-align:center; padding: 12px;">
@@ -238,6 +306,11 @@ Option Explicit
End If
%>
</td>
<td style="text-align:center; padding: 12px;">
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="shareKBArticle(<%=Server.HTMLEncode(kbLinkId)%>)" title="Copy link to this article">
<i class="zmdi zmdi-share"></i>
</button>
</td>
</tr>
<%
rsKB.MoveNext
@@ -288,7 +361,6 @@ Option Explicit
<option value='<%response.write(rs("supportteamid"))%>'><%Response.Write(rs("teamname"))%></option>
<%
' Get all support teams for dropdown (same pattern as displayprinter.asp)
Dim rsSupportTeams, sqlSupportTeams
sqlSupportTeams = "SELECT supporteamid, teamname FROM supportteams WHERE isactive=1 ORDER BY teamname ASC"
Set rsSupportTeams = objconn.Execute(sqlSupportTeams)
While Not rsSupportTeams.EOF
@@ -332,7 +404,6 @@ Option Explicit
<select class="form-control" id="newappownerid" name="newappownerid">
<option value="">-- Select App Owner --</option>
<%
Dim rsAppOwners, sqlAppOwners
sqlAppOwners = "SELECT appownerid, appowner FROM appowners WHERE isactive=1 ORDER BY appowner ASC"
Set rsAppOwners = objconn.Execute(sqlAppOwners)
While Not rsAppOwners.EOF
@@ -529,7 +600,61 @@ Option Explicit
<script src="assets/js/app-script.js"></script>
<script>
// Lightbox functions
function openLightbox() {
document.getElementById('imageLightbox').classList.add('active');
document.body.style.overflow = 'hidden';
}
function closeLightbox(event) {
document.getElementById('imageLightbox').classList.remove('active');
document.body.style.overflow = '';
}
// Close lightbox with Escape key
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
closeLightbox();
}
});
// Share KB article link with highlight parameter
function shareKBArticle(linkId) {
var url = window.location.protocol + '//' + window.location.host + window.location.pathname;
url += '?appid=<%=appid%>&highlight=' + linkId;
// Use fallback method for HTTP (clipboard API requires HTTPS)
var temp = document.createElement('textarea');
temp.value = url;
temp.style.position = 'fixed';
temp.style.left = '-9999px';
document.body.appendChild(temp);
temp.select();
document.execCommand('copy');
document.body.removeChild(temp);
// Show feedback
var btn = event.currentTarget;
var originalHTML = btn.innerHTML;
btn.innerHTML = '<i class="zmdi zmdi-check"></i>';
btn.classList.remove('btn-outline-secondary');
btn.classList.add('btn-success');
setTimeout(function() {
btn.innerHTML = originalHTML;
btn.classList.remove('btn-success');
btn.classList.add('btn-outline-secondary');
}, 1500);
}
$(document).ready(function() {
// Scroll to highlighted KB article if present
var highlightedRow = document.querySelector('.highlighted-result');
if (highlightedRow) {
setTimeout(function() {
highlightedRow.scrollIntoView({ behavior: 'smooth', block: 'center' });
}, 500);
}
// Show/hide new support team section
$('#addSupportTeamBtn, #supportteamid').on('change click', function() {
if ($('#supportteamid').val() === 'new' || $(this).attr('id') === 'addSupportTeamBtn') {