diff --git a/addknowledgebase.asp b/addknowledgebase.asp index e0200df..38e0946 100644 --- a/addknowledgebase.asp +++ b/addknowledgebase.asp @@ -61,10 +61,10 @@
- +
- + <% Dim strSQL, rsApps strSQL = "SELECT appid, appname FROM applications WHERE isactive = 1 ORDER BY appname ASC" diff --git a/addlinkdirect.asp b/addlinkdirect.asp index f7c4d37..8ee09f1 100644 --- a/addlinkdirect.asp +++ b/addlinkdirect.asp @@ -38,12 +38,19 @@ newappownername = Trim(Request.Form("newappownername")) newappownersso = Trim(Request.Form("newappownersso")) ' Basic validation for KB article -If Len(linkurl) = 0 Or Len(shortdescription) = 0 Or Len(appid) = 0 Then +If Len(linkurl) = 0 Or Len(shortdescription) = 0 Then Response.Write("Required fields missing") objConn.Close Response.End End If +' Basic validation for KB article +If Len(appid) = 0 Then + Response.Write("Topic is required") + objConn.Close + Response.End +End If + If Len(linkurl) > 2000 Or Len(shortdescription) > 500 Or Len(keywords) > 500 Then Response.Write("Field length exceeded") objConn.Close diff --git a/deviceaccesspoint.asp b/deviceaccesspoint.asp index 586748c..9663976 100644 --- a/deviceaccesspoint.asp +++ b/deviceaccesspoint.asp @@ -23,11 +23,11 @@ ' If editing, fetch existing data Dim rs, accesspointname, modelid, serialnumber, ipaddress, fqdn, description, maptop, mapleft, isactive - Dim vendorname, modelnumber + Dim vendorname, modelnumber, logicmonitorurl If Not isNewRecord Then Dim strSQL strSQL = "SELECT mac.machineid, mac.alias AS apname, mac.modelnumberid AS modelid, " & _ - "mac.serialnumber, mac.fqdn, mac.machinenotes AS description, mac.maptop, mac.mapleft, mac.isactive, " & _ + "mac.serialnumber, mac.fqdn, mac.logicmonitorurl, mac.machinenotes AS description, mac.maptop, mac.mapleft, mac.isactive, " & _ "m.modelnumber, v.vendor, c.address AS ipaddress " & _ "FROM machines mac " & _ "LEFT JOIN models m ON mac.modelnumberid = m.modelnumberid " & _ @@ -49,8 +49,9 @@ Else ipaddress = "" End If - If Not IsNull(rs("fqdn")) Then fqdn = rs("fqdn") Else fqdn = "" - If Not IsNull(rs("description")) Then description = rs("description") Else description = "" + If Not IsNull(rs("fqdn")) Then fqdn = rs("fqdn") & "" Else fqdn = "" + If Not IsNull(rs("logicmonitorurl")) Then logicmonitorurl = rs("logicmonitorurl") & "" Else logicmonitorurl = "" + description = rs("description") & "" If Not IsNull(rs("maptop")) Then maptop = rs("maptop") Else maptop = "" If Not IsNull(rs("mapleft")) Then mapleft = rs("mapleft") Else mapleft = "" If Not IsNull(rs("isactive")) Then isactive = rs("isactive") Else isactive = 1 @@ -66,6 +67,7 @@ serialnumber = "" ipaddress = "" fqdn = "" + logicmonitorurl = "" description = "" maptop = "" mapleft = "" @@ -138,12 +140,13 @@ + + Link to this device in Logic Monitor (optional) + +
+
+
diff --git a/devicecamera.asp b/devicecamera.asp index 6d99124..2dbf2b5 100644 --- a/devicecamera.asp +++ b/devicecamera.asp @@ -63,8 +63,8 @@ Else ipaddress = "" End If - If Not IsNull(rs("fqdn")) Then fqdn = rs("fqdn") Else fqdn = "" - If Not IsNull(rs("description")) Then description = rs("description") Else description = "" + If Not IsNull(rs("fqdn")) Then fqdn = rs("fqdn") & "" Else fqdn = "" + description = rs("description") & "" If Not IsNull(rs("maptop")) Then maptop = rs("maptop") Else maptop = "" If Not IsNull(rs("mapleft")) Then mapleft = rs("mapleft") Else mapleft = "" If Not IsNull(rs("isactive")) Then isactive = rs("isactive") Else isactive = 1 @@ -231,12 +231,13 @@ <% - Dim strSQL2, rsModels - ' Filter models to only show Server models (machinetypeid = 20) + Dim strSQL2, rsModels, currentModelId + ' Show Server models (machinetypeid = 20) plus currently assigned model + If IsNumeric(modelid) Then currentModelId = CLng(modelid) Else currentModelId = 0 strSQL2 = "SELECT m.modelnumberid, m.modelnumber, v.vendor " & _ "FROM models m " & _ "INNER JOIN vendors v ON m.vendorid = v.vendorid " & _ - "WHERE m.isactive = 1 AND m.machinetypeid = 20 " & _ + "WHERE m.isactive = 1 AND (m.machinetypeid = 20 OR m.modelnumberid = " & currentModelId & ") " & _ "ORDER BY v.vendor, m.modelnumber" Set rsModels = objConn.Execute(strSQL2) Do While Not rsModels.EOF @@ -301,6 +304,19 @@
+
+ +
+ + + Link to this device in Logic Monitor (optional) + +
+
+
@@ -312,6 +328,74 @@
+<%If Not isNewRecord Then%> +
+ +
+
+<% + ' Query applications currently assigned to this server + Dim rsCurrentApps, strAppSQL + strAppSQL = "SELECT ia.installedappid, a.appid, a.appname " & _ + "FROM installedapps ia " & _ + "INNER JOIN applications a ON ia.appid = a.appid " & _ + "WHERE ia.machineid = " & CLng(serverid) & " AND ia.isactive = 1 " & _ + "ORDER BY a.appname" + Set rsCurrentApps = objConn.Execute(strAppSQL) + If Not rsCurrentApps.EOF Then + Do While Not rsCurrentApps.EOF +%> + + <%=Server.HTMLEncode(rsCurrentApps("appname") & "")%> + "> + + +<% + rsCurrentApps.MoveNext + Loop + Else +%> + No applications assigned +<% + End If + rsCurrentApps.Close + Set rsCurrentApps = Nothing +%> +
+
+ +
+ +
+
+ + Select applications hosted on this server + + + +
+
+<%End If%> +
@@ -496,6 +580,63 @@ $(document).ready(function() { } } }); + + // Application management + var addedApps = []; + var removedApps = []; + + // Add application + $('#addAppBtn').on('click', function() { + var appId = $('#addAppSelect').val(); + var appName = $('#addAppSelect option:selected').text(); + if (appId && appId !== '') { + // Check if already added or already exists + if ($('#currentApps').find('[data-appid="' + appId + '"]').length > 0) { + alert('This application is already assigned to this server'); + return; + } + if (addedApps.indexOf(appId) >= 0) { + alert('This application has already been added'); + return; + } + addedApps.push(appId); + $('#appsInput').val(addedApps.join(',')); + + // Add badge + var badge = $('' + + appName + + '' + + ''); + if ($('#currentApps').find('.text-muted').length > 0) { + $('#currentApps').html(''); + } + $('#currentApps').append(badge); + $('#addAppSelect').val(''); + } + }); + + // Remove newly added application + $(document).on('click', '.btn-remove-new-app', function() { + var appId = $(this).data('appid').toString(); + addedApps = addedApps.filter(function(id) { return id !== appId; }); + $('#appsInput').val(addedApps.join(',')); + $(this).parent().remove(); + if ($('#currentApps').children().length === 0) { + $('#currentApps').html('No applications assigned'); + } + }); + + // Remove existing application + $(document).on('click', '.btn-remove-app', function() { + var appId = $(this).data('appid').toString(); + removedApps.push(appId); + $('#removedAppsInput').val(removedApps.join(',')); + $(this).parent().remove(); + if ($('#currentApps').children().length === 0) { + $('#currentApps').html('No applications assigned'); + } + }); }); diff --git a/deviceswitch.asp b/deviceswitch.asp index c6a861f..319a941 100644 --- a/deviceswitch.asp +++ b/deviceswitch.asp @@ -23,11 +23,11 @@ ' If editing, fetch existing data Dim rs, switchname, modelid, serialnumber, ipaddress, fqdn, description, maptop, mapleft, isactive - Dim vendorname, modelnumber + Dim vendorname, modelnumber, logicmonitorurl If Not isNewRecord Then Dim strSQL strSQL = "SELECT mac.machineid, mac.alias AS switchname, mac.modelnumberid AS modelid, " & _ - "mac.serialnumber, mac.fqdn, mac.machinenotes AS description, mac.maptop, mac.mapleft, mac.isactive, " & _ + "mac.serialnumber, mac.fqdn, mac.logicmonitorurl, mac.machinenotes AS description, mac.maptop, mac.mapleft, mac.isactive, " & _ "m.modelnumber, v.vendor, c.address AS ipaddress " & _ "FROM machines mac " & _ "LEFT JOIN models m ON mac.modelnumberid = m.modelnumberid " & _ @@ -45,8 +45,9 @@ If Not IsNull(rs("modelid")) Then modelid = rs("modelid") Else modelid = "" If Not IsNull(rs("serialnumber")) Then serialnumber = rs("serialnumber") Else serialnumber = "" If Not IsNull(rs("ipaddress")) Then ipaddress = rs("ipaddress") Else ipaddress = "" - If Not IsNull(rs("fqdn")) Then fqdn = rs("fqdn") Else fqdn = "" - If Not IsNull(rs("description")) Then description = rs("description") Else description = "" + If Not IsNull(rs("fqdn")) Then fqdn = rs("fqdn") & "" Else fqdn = "" + If Not IsNull(rs("logicmonitorurl")) Then logicmonitorurl = rs("logicmonitorurl") & "" Else logicmonitorurl = "" + description = rs("description") & "" If Not IsNull(rs("maptop")) Then maptop = rs("maptop") Else maptop = "" If Not IsNull(rs("mapleft")) Then mapleft = rs("mapleft") Else mapleft = "" If Not IsNull(rs("isactive")) Then isactive = rs("isactive") Else isactive = 1 @@ -62,6 +63,7 @@ serialnumber = "" ipaddress = "" fqdn = "" + logicmonitorurl = "" description = "" maptop = "" mapleft = "" @@ -134,12 +136,13 @@ + + Link to this device in Logic Monitor (optional) + +
+
+
diff --git a/displayapplication.asp b/displayapplication.asp index 0de2199..a17f4b6 100644 --- a/displayapplication.asp +++ b/displayapplication.asp @@ -1,12 +1,17 @@ <%@ Language=VBScript %> -<% -Option Explicit -%> <% - 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 +
+ + + +
@@ -63,7 +135,7 @@ Option Explicit
- " alt="Card image cap"> + " alt="<%=Server.HTMLEncode(rs("appname") & "")%>" onclick="openLightbox()" title="Click to enlarge">
" alt="profile-image" class="profile"> @@ -90,13 +162,19 @@ Option Explicit
<%=Server.HTMLEncode(rs("appname") & "")%>
+<% + Dim appDescription + appDescription = rs("appdescription") & "" + If appDescription <> "" Then + Response.Write("

" & Server.HTMLEncode(appDescription) & "

") + End If +%>

Support Team:

App Owner:

SSO:

<% - Dim installPath, docPath, appLink installPath = rs("installpath") & "" appLink = rs("applicationlink") & "" docPath = rs("documentationpath") & "" @@ -113,7 +191,6 @@ Option Explicit
<% - Dim teamUrl teamUrl = rs("teamurl") & "" If teamUrl <> "" Then Response.Write("

" & Server.HTMLEncode(rs("teamname")) & "

") @@ -137,43 +214,30 @@ Option Explicit
Application Notes
-
- - - - - - - - - -
- <%Response.Write(rs("appname"))%>: -
<%Response.Write(rs("applicationnotes"))%> -
-
+
+ + + + + + + + + +
+ <%=Server.HTMLEncode(rs("appname") & "")%>: +
<%=rs("applicationnotes") & ""%>
+
Related Knowledge Base Articles
<% - ' 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 Article - - Clicks - + Clicks + Share <% - ' 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 %> - + > - " + - <%=Server.HTMLEncode(kbDesc)%> + <%=Server.HTMLEncode(kbDesc)%> @@ -238,6 +306,11 @@ Option Explicit End If %> + + + <% rsKB.MoveNext @@ -288,7 +361,6 @@ Option Explicit <% ' 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 - - + + + + +
@@ -177,18 +207,19 @@ Set rsBadges = Nothing %>
-
- - Clear -
-
+
>
+
+ + Clear + +
@@ -442,6 +473,278 @@ rsTopOps.Close Set rsTopOps = Nothing If opLabels = "" Then opLabels = """No Data""" If opData = "" Then opData = "0" + +' ============================================================================ +' HISTORICAL TRENDS DATA (from summary tables - survives 90-day purge) +' ============================================================================ + +' Monthly measurement trends (last 12 months) +Dim rsMonthlyMeas, monthlyLabels, monthlyMeasData, monthlyOOTData, monthlyOOTRate +monthlyLabels = "" +monthlyMeasData = "" +monthlyOOTData = "" +monthlyOOTRate = "" +strSQL2 = "SELECT yearmonth, SUM(measurement_count) as total_meas, SUM(oot_count) as total_oot, " & _ + "ROUND(SUM(oot_count)*100.0/NULLIF(SUM(measurement_count),0), 2) as oot_rate " & _ + "FROM vwudcmeasurements_monthly " +If filterMachine <> "" Then + strSQL2 = strSQL2 & "WHERE machinenumber = '" & Replace(filterMachine, "'", "''") & "' " +End If +strSQL2 = strSQL2 & "GROUP BY yearmonth ORDER BY yearmonth DESC LIMIT 12" +Set rsMonthlyMeas = objConn.Execute(strSQL2) +Dim monthlyArr(11,3), monthlyIdx +monthlyIdx = 0 +Do While Not rsMonthlyMeas.EOF And monthlyIdx < 12 + monthlyArr(monthlyIdx, 0) = rsMonthlyMeas("yearmonth") & "" + monthlyArr(monthlyIdx, 1) = rsMonthlyMeas("total_meas") & "" + monthlyArr(monthlyIdx, 2) = rsMonthlyMeas("total_oot") & "" + If IsNull(rsMonthlyMeas("oot_rate")) Then + monthlyArr(monthlyIdx, 3) = "0" + Else + monthlyArr(monthlyIdx, 3) = rsMonthlyMeas("oot_rate") & "" + End If + monthlyIdx = monthlyIdx + 1 + rsMonthlyMeas.MoveNext +Loop +rsMonthlyMeas.Close +Set rsMonthlyMeas = Nothing +' Reverse order for chronological display +Dim mi +For mi = monthlyIdx - 1 To 0 Step -1 + If monthlyLabels <> "" Then monthlyLabels = monthlyLabels & "," + If monthlyMeasData <> "" Then monthlyMeasData = monthlyMeasData & "," + If monthlyOOTData <> "" Then monthlyOOTData = monthlyOOTData & "," + If monthlyOOTRate <> "" Then monthlyOOTRate = monthlyOOTRate & "," + monthlyLabels = monthlyLabels & """" & monthlyArr(mi, 0) & """" + monthlyMeasData = monthlyMeasData & monthlyArr(mi, 1) + monthlyOOTData = monthlyOOTData & monthlyArr(mi, 2) + monthlyOOTRate = monthlyOOTRate & monthlyArr(mi, 3) +Next +If monthlyLabels = "" Then monthlyLabels = """No Data""" +If monthlyMeasData = "" Then monthlyMeasData = "0" +If monthlyOOTData = "" Then monthlyOOTData = "0" +If monthlyOOTRate = "" Then monthlyOOTRate = "0" + +' Machine comparison from summaries (total measurements by machine, all time) +Dim rsMachHist, machHistLabels, machHistMeas, machHistOOT +machHistLabels = "" +machHistMeas = "" +machHistOOT = "" +strSQL2 = "SELECT machinenumber, SUM(measurement_count) as total_meas, SUM(oot_count) as total_oot " & _ + "FROM udcmeasurements_daily GROUP BY machinenumber ORDER BY total_meas DESC LIMIT 15" +Set rsMachHist = objConn.Execute(strSQL2) +Do While Not rsMachHist.EOF + If machHistLabels <> "" Then machHistLabels = machHistLabels & "," + If machHistMeas <> "" Then machHistMeas = machHistMeas & "," + If machHistOOT <> "" Then machHistOOT = machHistOOT & "," + machHistLabels = machHistLabels & """" & (rsMachHist("machinenumber") & "") & """" + machHistMeas = machHistMeas & (rsMachHist("total_meas") & "") + machHistOOT = machHistOOT & (rsMachHist("total_oot") & "") + rsMachHist.MoveNext +Loop +rsMachHist.Close +Set rsMachHist = Nothing +If machHistLabels = "" Then machHistLabels = """No Data""" +If machHistMeas = "" Then machHistMeas = "0" +If machHistOOT = "" Then machHistOOT = "0" + +' Weekly trends for the last 26 weeks +Dim rsWeeklyTrend, weeklyLabels, weeklyMeasData, weeklyOOTRate +weeklyLabels = "" +weeklyMeasData = "" +weeklyOOTRate = "" +strSQL2 = "SELECT week_start, SUM(measurement_count) as total_meas, " & _ + "ROUND(SUM(oot_count)*100.0/NULLIF(SUM(measurement_count),0), 2) as oot_rate " & _ + "FROM vwudcmeasurements_weekly " +If filterMachine <> "" Then + strSQL2 = strSQL2 & "WHERE machinenumber = '" & Replace(filterMachine, "'", "''") & "' " +End If +strSQL2 = strSQL2 & "GROUP BY yearweek, week_start ORDER BY week_start DESC LIMIT 26" +Set rsWeeklyTrend = objConn.Execute(strSQL2) +Dim weeklyArr(25,2), weeklyIdx +weeklyIdx = 0 +Do While Not rsWeeklyTrend.EOF And weeklyIdx < 26 + weeklyArr(weeklyIdx, 0) = Month(rsWeeklyTrend("week_start")) & "/" & Day(rsWeeklyTrend("week_start")) + weeklyArr(weeklyIdx, 1) = rsWeeklyTrend("total_meas") & "" + If IsNull(rsWeeklyTrend("oot_rate")) Then + weeklyArr(weeklyIdx, 2) = "0" + Else + weeklyArr(weeklyIdx, 2) = rsWeeklyTrend("oot_rate") & "" + End If + weeklyIdx = weeklyIdx + 1 + rsWeeklyTrend.MoveNext +Loop +rsWeeklyTrend.Close +Set rsWeeklyTrend = Nothing +' Reverse for chronological +Dim wi +For wi = weeklyIdx - 1 To 0 Step -1 + If weeklyLabels <> "" Then weeklyLabels = weeklyLabels & "," + If weeklyMeasData <> "" Then weeklyMeasData = weeklyMeasData & "," + If weeklyOOTRate <> "" Then weeklyOOTRate = weeklyOOTRate & "," + weeklyLabels = weeklyLabels & """" & weeklyArr(wi, 0) & """" + weeklyMeasData = weeklyMeasData & weeklyArr(wi, 1) + weeklyOOTRate = weeklyOOTRate & weeklyArr(wi, 2) +Next +If weeklyLabels = "" Then weeklyLabels = """No Data""" +If weeklyMeasData = "" Then weeklyMeasData = "0" +If weeklyOOTRate = "" Then weeklyOOTRate = "0" + +' Monthly parts production trends (from udcpartsdaily) +Dim rsMonthlyParts, monthlyPartsLabels, monthlyPartsData +monthlyPartsLabels = "" +monthlyPartsData = "" +strSQL2 = "SELECT yearmonth, SUM(partscount) as total_parts " & _ + "FROM vwudcparts_monthly " +If filterMachine <> "" Then + strSQL2 = strSQL2 & "WHERE machinenumber = '" & Replace(filterMachine, "'", "''") & "' " +End If +strSQL2 = strSQL2 & "GROUP BY yearmonth ORDER BY yearmonth DESC LIMIT 12" +Set rsMonthlyParts = objConn.Execute(strSQL2) +Dim partsArr(11,1), partsIdx +partsIdx = 0 +Do While Not rsMonthlyParts.EOF And partsIdx < 12 + partsArr(partsIdx, 0) = rsMonthlyParts("yearmonth") & "" + partsArr(partsIdx, 1) = rsMonthlyParts("total_parts") & "" + partsIdx = partsIdx + 1 + rsMonthlyParts.MoveNext +Loop +rsMonthlyParts.Close +Set rsMonthlyParts = Nothing +Dim pi +For pi = partsIdx - 1 To 0 Step -1 + If monthlyPartsLabels <> "" Then monthlyPartsLabels = monthlyPartsLabels & "," + If monthlyPartsData <> "" Then monthlyPartsData = monthlyPartsData & "," + monthlyPartsLabels = monthlyPartsLabels & """" & partsArr(pi, 0) & """" + monthlyPartsData = monthlyPartsData & partsArr(pi, 1) +Next +If monthlyPartsLabels = "" Then monthlyPartsLabels = """No Data""" +If monthlyPartsData = "" Then monthlyPartsData = "0" + +' Monthly response time trends (from udcmanualrequestsdaily) +Dim rsMonthlyResp, monthlyRespLabels, monthlyRespData +monthlyRespLabels = "" +monthlyRespData = "" +strSQL2 = "SELECT yearmonth, ROUND(AVG(avgresponseseconds), 1) as avg_resp " & _ + "FROM vwudcmanualrequests_monthly " +If filterMachine <> "" Then + strSQL2 = strSQL2 & "WHERE machinenumber = '" & Replace(filterMachine, "'", "''") & "' " +End If +strSQL2 = strSQL2 & "GROUP BY yearmonth ORDER BY yearmonth DESC LIMIT 12" +Set rsMonthlyResp = objConn.Execute(strSQL2) +Dim respArr(11,1), respIdx +respIdx = 0 +Do While Not rsMonthlyResp.EOF And respIdx < 12 + respArr(respIdx, 0) = rsMonthlyResp("yearmonth") & "" + If IsNull(rsMonthlyResp("avg_resp")) Then + respArr(respIdx, 1) = "0" + Else + respArr(respIdx, 1) = rsMonthlyResp("avg_resp") & "" + End If + respIdx = respIdx + 1 + rsMonthlyResp.MoveNext +Loop +rsMonthlyResp.Close +Set rsMonthlyResp = Nothing +Dim ri +For ri = respIdx - 1 To 0 Step -1 + If monthlyRespLabels <> "" Then monthlyRespLabels = monthlyRespLabels & "," + If monthlyRespData <> "" Then monthlyRespData = monthlyRespData & "," + monthlyRespLabels = monthlyRespLabels & """" & respArr(ri, 0) & """" + monthlyRespData = monthlyRespData & respArr(ri, 1) +Next +If monthlyRespLabels = "" Then monthlyRespLabels = """No Data""" +If monthlyRespData = "" Then monthlyRespData = "0" + +' Monthly violations trends (CLM specific) +Dim rsMonthlyViol, monthlyViolLabels, monthlyViolData +monthlyViolLabels = "" +monthlyViolData = "" +strSQL2 = "SELECT yearmonth, SUM(violationcount) as total_violations " & _ + "FROM vwudcviolations_monthly " +If filterMachine <> "" Then + strSQL2 = strSQL2 & "WHERE machinenumber = '" & Replace(filterMachine, "'", "''") & "' " +End If +strSQL2 = strSQL2 & "GROUP BY yearmonth ORDER BY yearmonth DESC LIMIT 12" +Set rsMonthlyViol = objConn.Execute(strSQL2) +Dim violArr(11,1), violIdx +violIdx = 0 +Do While Not rsMonthlyViol.EOF And violIdx < 12 + violArr(violIdx, 0) = rsMonthlyViol("yearmonth") & "" + If IsNull(rsMonthlyViol("total_violations")) Then + violArr(violIdx, 1) = "0" + Else + violArr(violIdx, 1) = rsMonthlyViol("total_violations") & "" + End If + violIdx = violIdx + 1 + rsMonthlyViol.MoveNext +Loop +rsMonthlyViol.Close +Set rsMonthlyViol = Nothing +Dim vi +For vi = violIdx - 1 To 0 Step -1 + If monthlyViolLabels <> "" Then monthlyViolLabels = monthlyViolLabels & "," + If monthlyViolData <> "" Then monthlyViolData = monthlyViolData & "," + monthlyViolLabels = monthlyViolLabels & """" & violArr(vi, 0) & """" + monthlyViolData = monthlyViolData & violArr(vi, 1) +Next +If monthlyViolLabels = "" Then monthlyViolLabels = """No Data""" +If monthlyViolData = "" Then monthlyViolData = "0" + +' Monthly changeover time trends +Dim rsMonthlyChg, monthlyChgLabels, monthlyChgData +monthlyChgLabels = "" +monthlyChgData = "" +strSQL2 = "SELECT yearmonth, ROUND(AVG(avgchangeover)/60, 1) as avg_changeover_min " & _ + "FROM vwudcchangeover_monthly " +If filterMachine <> "" Then + strSQL2 = strSQL2 & "WHERE machinenumber = '" & Replace(filterMachine, "'", "''") & "' " +End If +strSQL2 = strSQL2 & "GROUP BY yearmonth ORDER BY yearmonth DESC LIMIT 12" +Set rsMonthlyChg = objConn.Execute(strSQL2) +Dim chgArr(11,1), chgIdx +chgIdx = 0 +Do While Not rsMonthlyChg.EOF And chgIdx < 12 + chgArr(chgIdx, 0) = rsMonthlyChg("yearmonth") & "" + If IsNull(rsMonthlyChg("avg_changeover_min")) Then + chgArr(chgIdx, 1) = "0" + Else + chgArr(chgIdx, 1) = rsMonthlyChg("avg_changeover_min") & "" + End If + chgIdx = chgIdx + 1 + rsMonthlyChg.MoveNext +Loop +rsMonthlyChg.Close +Set rsMonthlyChg = Nothing +Dim ci +For ci = chgIdx - 1 To 0 Step -1 + If monthlyChgLabels <> "" Then monthlyChgLabels = monthlyChgLabels & "," + If monthlyChgData <> "" Then monthlyChgData = monthlyChgData & "," + monthlyChgLabels = monthlyChgLabels & """" & chgArr(ci, 0) & """" + monthlyChgData = monthlyChgData & chgArr(ci, 1) +Next +If monthlyChgLabels = "" Then monthlyChgLabels = """No Data""" +If monthlyChgData = "" Then monthlyChgData = "0" + +' Violations by machine (top 10) +Dim rsViolByMachine, violMachLabels, violMachData +violMachLabels = "" +violMachData = "" +strSQL2 = "SELECT machinenumber, SUM(violationcount) as total_violations " & _ + "FROM vwudcviolations_monthly " & _ + "GROUP BY machinenumber ORDER BY total_violations DESC LIMIT 10" +Set rsViolByMachine = objConn.Execute(strSQL2) +Do While Not rsViolByMachine.EOF + If violMachLabels <> "" Then violMachLabels = violMachLabels & "," + If violMachData <> "" Then violMachData = violMachData & "," + violMachLabels = violMachLabels & """" & rsViolByMachine("machinenumber") & """" + violMachData = violMachData & rsViolByMachine("total_violations") + rsViolByMachine.MoveNext +Loop +rsViolByMachine.Close +Set rsViolByMachine = Nothing +If violMachLabels = "" Then violMachLabels = """No Data""" +If violMachData = "" Then violMachData = "0" %> @@ -451,10 +754,10 @@ If opData = "" Then opData = "0"
" id="dashboard"> -
UDC Performance Dashboard
+
UDC Performance Dashboard
- Production Trend + Production Trend
@@ -507,7 +813,7 @@ If opData = "" Then opData = "0"
- OOT Rate Trend + OOT Rate Trend
@@ -523,7 +829,7 @@ If opData = "" Then opData = "0"
- Machine Utilization (Hours) + Machine Utilization (Hours)
@@ -535,7 +841,7 @@ If opData = "" Then opData = "0"
- Top Operators (Parts) + Top Operators (Parts)
@@ -549,7 +855,7 @@ If opData = "" Then opData = "0"
" id="liveactivity"> -
Active Machines Live
+
Active Machines Live

Machines currently running jobs. Data refreshes when page loads.

<% ' Get active sessions with optional machine/BU filter @@ -569,7 +875,7 @@ activeCount = 0 If rsActive.EOF Then %>
- No active jobs detected + No active jobs detected
<% Else @@ -2001,6 +2307,204 @@ Set rsRecentConn = Nothing
+ +
" id="trends"> +
+ Historical Data: This data comes from daily summaries and includes all historical data beyond the 90-day retention period. Individual measurements are aggregated into daily/weekly/monthly totals. +
+ + +
+
+
+
+ Monthly Measurement Trend (12 Months) +
+
+
+ +
+
+
+
+
+
+
+ Monthly OOT Rate Trend +
+
+
+ +
+
+
+
+
+ + +
+
+
+
+ Monthly Production Trend (Parts) +
+
+
+ +
+
+
+
+
+
+
+ Monthly Avg Response Time (seconds) +
+
+
+ +
+
+
+
+
+ + +
+
+
+
+ Weekly Measurement Trend (26 Weeks) +
+
+
+ +
+
+
+
+
+
+
+ All-Time Machine Comparison (Top 15) +
+
+
+ +
+
+
+
+
+ + +
+
+
+
+ Monthly Parameter Violations (CLM) +
+
+
+ +
+
+
+
+
+
+
+ Monthly Avg Changeover Time (minutes) +
+
+
+ +
+
+
+
+
+ + +
+
+
+
+ Violations by Machine (All Time Top 10) +
+
+
+ +
+
+
+
+
+
+
+ CLM Data Notes +
+
+

Parameter Violations: Tracked when operators change machine parameters outside allowed limits during CLM runs. High violation counts may indicate calibration issues or training needs.

+

Changeover Time: Time between consecutive part runs on the same machine. Helps identify efficiency opportunities and scheduling patterns.

+

Note: CLM data comes from JSON files in CLM_Data folder. Violations and changeover times are only tracked for CLM sessions, not UDC log sessions.

+
+
+
+
+ + +
+
+ Monthly Summary Data +
+
+
+ + + + + + + + + + +<% +Dim rsMonthlySummary +strSQL2 = "SELECT yearmonth, SUM(measurement_count) as total_meas, SUM(oot_count) as total_oot, " & _ + "ROUND(SUM(oot_count)*100.0/NULLIF(SUM(measurement_count),0), 2) as oot_rate " & _ + "FROM vwudcmeasurements_monthly " +If filterMachine <> "" Then + strSQL2 = strSQL2 & "WHERE machinenumber = '" & Replace(filterMachine, "'", "''") & "' " +End If +strSQL2 = strSQL2 & "GROUP BY yearmonth ORDER BY yearmonth DESC LIMIT 24" +Set rsMonthlySummary = objConn.Execute(strSQL2) +Do While Not rsMonthlySummary.EOF + Dim ootRateVal + If IsNull(rsMonthlySummary("oot_rate")) Then + ootRateVal = "0.00" + Else + ootRateVal = rsMonthlySummary("oot_rate") & "" + End If + Response.Write("") + Response.Write("") + Response.Write("") + Response.Write("") + Response.Write("") + Response.Write("") + rsMonthlySummary.MoveNext +Loop +rsMonthlySummary.Close +Set rsMonthlySummary = Nothing +%> + +
MonthTotal MeasurementsOOT CountOOT Rate
" & Server.HTMLEncode(rsMonthlySummary("yearmonth") & "") & "" & Server.HTMLEncode(FormatNumber(rsMonthlySummary("total_meas"), 0)) & "" & Server.HTMLEncode(FormatNumber(rsMonthlySummary("total_oot"), 0)) & "" & Server.HTMLEncode(ootRateVal) & "%
+
+
+
+
+
@@ -2032,6 +2536,22 @@ function setActiveTab(tabName) { document.getElementById('activeTabInput').value = tabName; } +// Copy current URL with filters to clipboard +function copyFilterLink(btn) { + var url = window.location.href; + var temp = document.createElement('textarea'); + temp.value = url; + document.body.appendChild(temp); + temp.select(); + document.execCommand('copy'); + document.body.removeChild(temp); + + // Brief feedback + var original = btn.innerHTML; + btn.innerHTML = 'Copied!'; + setTimeout(function() { btn.innerHTML = original; }, 1000); +} + // Dashboard Charts $(function() { // Chart 1: Production Trend (Line Chart) @@ -2163,6 +2683,260 @@ $(function() { } } }); + + // ======================================== + // Historical Trends Charts (from summaries) + // ======================================== + + // Monthly Measurement Trend + var ctxMonthlyMeas = document.getElementById('monthlyMeasChart'); + if (ctxMonthlyMeas) { + new Chart(ctxMonthlyMeas.getContext('2d'), { + type: 'bar', + data: { + labels: [<%=monthlyLabels%>], + datasets: [{ + label: 'Measurements', + data: [<%=monthlyMeasData%>], + backgroundColor: 'rgba(23, 162, 184, 0.7)', + borderColor: 'rgba(23, 162, 184, 1)', + borderWidth: 1 + }] + }, + options: { + maintainAspectRatio: false, + legend: { display: false }, + scales: { + yAxes: [{ ticks: { beginAtZero: true } }], + xAxes: [{ gridLines: { display: false } }] + } + } + }); + } + + // Monthly OOT Rate Trend + var ctxMonthlyOOT = document.getElementById('monthlyOOTChart'); + if (ctxMonthlyOOT) { + new Chart(ctxMonthlyOOT.getContext('2d'), { + type: 'line', + data: { + labels: [<%=monthlyLabels%>], + datasets: [{ + label: 'OOT Rate %', + data: [<%=monthlyOOTRate%>], + backgroundColor: 'rgba(220, 53, 69, 0.2)', + borderColor: 'rgba(220, 53, 69, 1)', + borderWidth: 2, + pointBackgroundColor: 'rgba(220, 53, 69, 1)', + pointRadius: 4, + fill: true + }] + }, + options: { + maintainAspectRatio: false, + legend: { display: false }, + scales: { + yAxes: [{ ticks: { beginAtZero: true, callback: function(v) { return v + '%'; } } }], + xAxes: [{ gridLines: { display: false } }] + } + } + }); + } + + // Weekly Measurement Trend + var ctxWeeklyMeas = document.getElementById('weeklyMeasChart'); + if (ctxWeeklyMeas) { + new Chart(ctxWeeklyMeas.getContext('2d'), { + type: 'line', + data: { + labels: [<%=weeklyLabels%>], + datasets: [{ + label: 'Measurements', + data: [<%=weeklyMeasData%>], + backgroundColor: 'rgba(102, 126, 234, 0.2)', + borderColor: 'rgba(102, 126, 234, 1)', + borderWidth: 2, + pointBackgroundColor: 'rgba(102, 126, 234, 1)', + pointRadius: 3, + fill: true + }] + }, + options: { + maintainAspectRatio: false, + legend: { display: false }, + scales: { + yAxes: [{ ticks: { beginAtZero: true } }], + xAxes: [{ gridLines: { display: false } }] + } + } + }); + } + + // Machine Historical Comparison + var ctxMachHist = document.getElementById('machineHistChart'); + if (ctxMachHist) { + new Chart(ctxMachHist.getContext('2d'), { + type: 'horizontalBar', + data: { + labels: [<%=machHistLabels%>], + datasets: [{ + label: 'Total Measurements', + data: [<%=machHistMeas%>], + backgroundColor: 'rgba(108, 117, 125, 0.7)', + borderColor: 'rgba(108, 117, 125, 1)', + borderWidth: 1 + }] + }, + options: { + maintainAspectRatio: false, + legend: { display: false }, + scales: { + xAxes: [{ ticks: { beginAtZero: true } }], + yAxes: [{ gridLines: { display: false } }] + } + } + }); + } + + // Monthly Parts Production Trend + var ctxMonthlyParts = document.getElementById('monthlyPartsChart'); + if (ctxMonthlyParts) { + new Chart(ctxMonthlyParts.getContext('2d'), { + type: 'bar', + data: { + labels: [<%=monthlyPartsLabels%>], + datasets: [{ + label: 'Parts Produced', + data: [<%=monthlyPartsData%>], + backgroundColor: 'rgba(40, 167, 69, 0.7)', + borderColor: 'rgba(40, 167, 69, 1)', + borderWidth: 1 + }] + }, + options: { + maintainAspectRatio: false, + legend: { display: false }, + scales: { + yAxes: [{ ticks: { beginAtZero: true } }], + xAxes: [{ gridLines: { display: false } }] + } + } + }); + } + + // Monthly Response Time Trend + var ctxMonthlyResp = document.getElementById('monthlyResponseChart'); + if (ctxMonthlyResp) { + new Chart(ctxMonthlyResp.getContext('2d'), { + type: 'line', + data: { + labels: [<%=monthlyRespLabels%>], + datasets: [{ + label: 'Avg Response (sec)', + data: [<%=monthlyRespData%>], + backgroundColor: 'rgba(255, 193, 7, 0.2)', + borderColor: 'rgba(255, 193, 7, 1)', + borderWidth: 2, + pointBackgroundColor: 'rgba(255, 193, 7, 1)', + pointRadius: 4, + fill: true + }] + }, + options: { + maintainAspectRatio: false, + legend: { display: false }, + scales: { + yAxes: [{ ticks: { beginAtZero: true, callback: function(v) { return v + 's'; } } }], + xAxes: [{ gridLines: { display: false } }] + } + } + }); + } + + // ======================================== + // CLM-Specific Charts + // ======================================== + + // Monthly Violations Trend (CLM) + var ctxMonthlyViol = document.getElementById('monthlyViolChart'); + if (ctxMonthlyViol) { + new Chart(ctxMonthlyViol.getContext('2d'), { + type: 'bar', + data: { + labels: [<%=monthlyViolLabels%>], + datasets: [{ + label: 'Violations', + data: [<%=monthlyViolData%>], + backgroundColor: 'rgba(220, 53, 69, 0.7)', + borderColor: 'rgba(220, 53, 69, 1)', + borderWidth: 1 + }] + }, + options: { + maintainAspectRatio: false, + legend: { display: false }, + scales: { + yAxes: [{ ticks: { beginAtZero: true } }], + xAxes: [{ gridLines: { display: false } }] + } + } + }); + } + + // Monthly Changeover Time Trend + var ctxMonthlyChg = document.getElementById('monthlyChangeoverChart'); + if (ctxMonthlyChg) { + new Chart(ctxMonthlyChg.getContext('2d'), { + type: 'line', + data: { + labels: [<%=monthlyChgLabels%>], + datasets: [{ + label: 'Avg Changeover (min)', + data: [<%=monthlyChgData%>], + backgroundColor: 'rgba(23, 162, 184, 0.2)', + borderColor: 'rgba(23, 162, 184, 1)', + borderWidth: 2, + pointBackgroundColor: 'rgba(23, 162, 184, 1)', + pointRadius: 4, + fill: true + }] + }, + options: { + maintainAspectRatio: false, + legend: { display: false }, + scales: { + yAxes: [{ ticks: { beginAtZero: true, callback: function(v) { return v + ' min'; } } }], + xAxes: [{ gridLines: { display: false } }] + } + } + }); + } + + // Violations by Machine (Horizontal Bar) + var ctxViolMach = document.getElementById('violByMachineChart'); + if (ctxViolMach) { + new Chart(ctxViolMach.getContext('2d'), { + type: 'horizontalBar', + data: { + labels: [<%=violMachLabels%>], + datasets: [{ + label: 'Violations', + data: [<%=violMachData%>], + backgroundColor: 'rgba(111, 66, 193, 0.7)', + borderColor: 'rgba(111, 66, 193, 1)', + borderWidth: 1 + }] + }, + options: { + maintainAspectRatio: false, + legend: { display: false }, + scales: { + xAxes: [{ ticks: { beginAtZero: true } }], + yAxes: [{ gridLines: { display: false } }] + } + } + }); + } }); diff --git a/editlink.asp b/editlink.asp index 5067a67..ee6758b 100644 --- a/editlink.asp +++ b/editlink.asp @@ -96,19 +96,23 @@
- +
- + <% - ' Get all support teams for dropdown - Dim rsApps, sqlApps + ' Get all applications for dropdown + Dim rsApps, sqlApps, currentAppId + currentAppId = rs("appid") & "" sqlApps = "SELECT appid, appname FROM applications WHERE isactive = 1 ORDER BY appname ASC" Set rsApps = objconn.Execute(sqlApps) While Not rsApps.EOF - If CLng(rsApps("appid")) <> CLng(rs("appid")) Then - Response.Write("") + Dim selectedAttr + selectedAttr = "" + If currentAppId <> "" And CStr(rsApps("appid")) = currentAppId Then + selectedAttr = " selected" End If + Response.Write("") rsApps.MoveNext Wend rsApps.Close diff --git a/editprinter.asp b/editprinter.asp index 35a7c16..8450f77 100644 --- a/editprinter.asp +++ b/editprinter.asp @@ -181,6 +181,11 @@ On Error Goto 0 End If + ' Auto-generate FQDN from IP if IP was changed + If ipaddress <> "" Then + fqdn = "Printer-" & Replace(ipaddress, ".", "-") & ".printer.geaerospace.net" + End If + ' Handle map coordinates - default to 50 if not provided Dim maptopValue, mapleftValue If maptop <> "" And IsNumeric(maptop) Then diff --git a/includes/leftsidebar.asp b/includes/leftsidebar.asp index f293e75..def49fe 100644 --- a/includes/leftsidebar.asp +++ b/includes/leftsidebar.asp @@ -1,33 +1,28 @@ <% -' Calculate fiscal week (GE fiscal year starts first Monday of January) -Dim fwToday, fwYearStart, fwFirstMonday, fwDayOfWeek, fwDaysFromStart, fiscalWeek -Dim fwPrevYearStart, fwPrevFirstMonday, fwPrevDayOfWeek +' Calculate ISO week number +' ISO week 1 is the week containing the first Thursday of the year (or Jan 4th) +' Weeks start on Monday +Dim fwToday, fiscalWeek, fwDayOfWeek, fwThursday, fwYear, fwJan4, fwWeek1Start, fwDaysFromStart + fwToday = Date() -' Find first Monday of current year -fwYearStart = DateSerial(Year(fwToday), 1, 1) -fwDayOfWeek = Weekday(fwYearStart, vbMonday) ' 1=Monday, 7=Sunday -If fwDayOfWeek = 1 Then - fwFirstMonday = fwYearStart -Else - fwFirstMonday = DateAdd("d", 8 - fwDayOfWeek, fwYearStart) -End If +' Find Thursday of current week (ISO weeks are identified by their Thursday) +fwDayOfWeek = Weekday(fwToday, vbMonday) ' 1=Monday ... 7=Sunday +fwThursday = DateAdd("d", 4 - fwDayOfWeek, fwToday) -' If we're before the first Monday, use previous year's week count -If fwToday < fwFirstMonday Then - fwPrevYearStart = DateSerial(Year(fwToday) - 1, 1, 1) - fwPrevDayOfWeek = Weekday(fwPrevYearStart, vbMonday) - If fwPrevDayOfWeek = 1 Then - fwPrevFirstMonday = fwPrevYearStart - Else - fwPrevFirstMonday = DateAdd("d", 8 - fwPrevDayOfWeek, fwPrevYearStart) - End If - fwDaysFromStart = DateDiff("d", fwPrevFirstMonday, fwToday) - fiscalWeek = Int(fwDaysFromStart / 7) + 1 -Else - fwDaysFromStart = DateDiff("d", fwFirstMonday, fwToday) - fiscalWeek = Int(fwDaysFromStart / 7) + 1 -End If +' The year of the Thursday determines the ISO year +fwYear = Year(fwThursday) + +' Find January 4th of that year (always in week 1) +fwJan4 = DateSerial(fwYear, 1, 4) + +' Find Monday of the week containing Jan 4 (start of week 1) +fwDayOfWeek = Weekday(fwJan4, vbMonday) +fwWeek1Start = DateAdd("d", 1 - fwDayOfWeek, fwJan4) + +' Calculate week number +fwDaysFromStart = DateDiff("d", fwWeek1Start, fwToday) +fiscalWeek = Int(fwDaysFromStart / 7) + 1 %>
Search Results
diff --git a/shopfloor-dashboard/index.html b/shopfloor-dashboard/index.html index 68fb82c..0a2edba 100644 --- a/shopfloor-dashboard/index.html +++ b/shopfloor-dashboard/index.html @@ -725,27 +725,30 @@ return urlParams.get('businessunit') || ''; } - // Calculate fiscal week (GE fiscal year starts first Monday of January) + // Calculate ISO week number + // ISO week 1 is the week containing the first Thursday of the year (or Jan 4th) + // Weeks start on Monday function getFiscalWeek() { const today = new Date(); - const year = today.getFullYear(); - // Find first Monday of current year - let jan1 = new Date(year, 0, 1); - let dayOfWeek = jan1.getDay(); // 0=Sunday, 1=Monday, etc. - let daysToMonday = (dayOfWeek === 0) ? 1 : (dayOfWeek === 1) ? 0 : (8 - dayOfWeek); - let firstMonday = new Date(year, 0, 1 + daysToMonday); + // Find Thursday of current week (ISO weeks are identified by their Thursday) + const dayOfWeek = (today.getDay() + 6) % 7; // 0=Monday, 6=Sunday + const thursday = new Date(today); + thursday.setDate(today.getDate() - dayOfWeek + 3); - // If we're before the first Monday, use previous year - if (today < firstMonday) { - let prevJan1 = new Date(year - 1, 0, 1); - let prevDayOfWeek = prevJan1.getDay(); - let prevDaysToMonday = (prevDayOfWeek === 0) ? 1 : (prevDayOfWeek === 1) ? 0 : (8 - prevDayOfWeek); - firstMonday = new Date(year - 1, 0, 1 + prevDaysToMonday); - } + // The year of the Thursday determines the ISO year + const isoYear = thursday.getFullYear(); - // Calculate days from first Monday - const diffTime = today - firstMonday; + // Find January 4th of that year (always in week 1) + const jan4 = new Date(isoYear, 0, 4); + + // Find Monday of the week containing Jan 4 (start of week 1) + const jan4DayOfWeek = (jan4.getDay() + 6) % 7; + const week1Start = new Date(jan4); + week1Start.setDate(jan4.getDate() - jan4DayOfWeek); + + // Calculate week number + const diffTime = today - week1Start; const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24)); const fiscalWeek = Math.floor(diffDays / 7) + 1; diff --git a/sql/ednc_tables.sql b/sql/ednc_tables.sql deleted file mode 100644 index 208728c..0000000 --- a/sql/ednc_tables.sql +++ /dev/null @@ -1,39 +0,0 @@ --- ============================================================================ --- eDNC Special Character Fix - Database Setup --- Run on PRODUCTION to create ednclogs table --- Created: 2025-12-12 --- ============================================================================ - --- Create ednclogs table (uses machineid FK to machines table) -CREATE TABLE IF NOT EXISTS ednclogs ( - logid INT AUTO_INCREMENT PRIMARY KEY, - machineid INT NOT NULL, - filename VARCHAR(255) NOT NULL, - action ENUM('cleaned', 'ok', 'failed', 'error', 'started', 'stopped') NOT NULL, - bytes_removed INT DEFAULT 0, - version VARCHAR(20), - message VARCHAR(500), - created DATETIME DEFAULT CURRENT_TIMESTAMP, - INDEX idx_machineid (machineid), - INDEX idx_created (created), - INDEX idx_action (action) -) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; - --- View for easy querying (includes hostname from machines) -CREATE OR REPLACE VIEW vw_ednclogs AS -SELECT - l.logid, - l.machineid, - m.hostname, - l.filename, - l.action, - l.bytes_removed, - l.version, - l.message, - l.created -FROM ednclogs l -INNER JOIN machines m ON l.machineid = m.machineid; - --- Verify -DESCRIBE ednclogs; -SELECT 'View created: vw_ednclogs' AS status; diff --git a/sql/udc_retention.sql b/sql/udc_retention.sql index 59f90bb..f86164c 100644 --- a/sql/udc_retention.sql +++ b/sql/udc_retention.sql @@ -53,6 +53,82 @@ CREATE TABLE IF NOT EXISTS udctooldata_daily ( INDEX idx_toolnumber (toolnumber) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; +-- Daily parts/production summary (aggregated from udcparts) +CREATE TABLE IF NOT EXISTS udcpartsdaily ( + summaryid INT AUTO_INCREMENT PRIMARY KEY, + summarydate DATE NOT NULL, + machinenumber VARCHAR(20) NOT NULL, + badgenumber VARCHAR(50), + partscount INT DEFAULT 0, + ootparts INT DEFAULT 0, + totalmeasurements INT DEFAULT 0, + totaloot INT DEFAULT 0, + avgcycletime DECIMAL(10,2), + mincycletime DECIMAL(10,2), + maxcycletime DECIMAL(10,2), + avgchangeover DECIMAL(10,2), + dateadded DATETIME DEFAULT CURRENT_TIMESTAMP, + UNIQUE INDEX uk_daily_machine_badge (summarydate, machinenumber, badgenumber), + INDEX idx_summarydate (summarydate), + INDEX idx_machinenumber (machinenumber), + INDEX idx_badgenumber (badgenumber) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- Daily manual request summary (aggregated from udcmanualrequests) +CREATE TABLE IF NOT EXISTS udcmanualrequestsdaily ( + summaryid INT AUTO_INCREMENT PRIMARY KEY, + summarydate DATE NOT NULL, + machinenumber VARCHAR(20) NOT NULL, + requestcount INT DEFAULT 0, + avgresponseseconds DECIMAL(10,2), + minresponseseconds DECIMAL(10,2), + maxresponseseconds DECIMAL(10,2), + dateadded DATETIME DEFAULT CURRENT_TIMESTAMP, + UNIQUE INDEX uk_daily_machine_manual (summarydate, machinenumber), + INDEX idx_summarydate (summarydate), + INDEX idx_machinenumber (machinenumber) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- Daily error summary (aggregated from udcerrors) +CREATE TABLE IF NOT EXISTS udcerrorsdaily ( + summaryid INT AUTO_INCREMENT PRIMARY KEY, + summarydate DATE NOT NULL, + machinenumber VARCHAR(20) NOT NULL, + errortype VARCHAR(50), + errorcount INT DEFAULT 0, + dateadded DATETIME DEFAULT CURRENT_TIMESTAMP, + UNIQUE INDEX uk_daily_machine_error (summarydate, machinenumber, errortype), + INDEX idx_summarydate (summarydate), + INDEX idx_machinenumber (machinenumber) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- Daily violation summary (aggregated from udcviolations - CLM specific) +CREATE TABLE IF NOT EXISTS udcviolationsdaily ( + summaryid INT AUTO_INCREMENT PRIMARY KEY, + summarydate DATE NOT NULL, + machinenumber VARCHAR(20) NOT NULL, + badgenumber VARCHAR(20), + violationcount INT DEFAULT 0, + dateadded DATETIME DEFAULT CURRENT_TIMESTAMP, + UNIQUE INDEX uk_daily_machine_badge_viol (summarydate, machinenumber, badgenumber), + INDEX idx_summarydate (summarydate), + INDEX idx_machinenumber (machinenumber), + INDEX idx_badgenumber (badgenumber) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- Daily header updates summary (aggregated from udcheaderupdates - badge changes) +CREATE TABLE IF NOT EXISTS udcheaderupdatesdaily ( + summaryid INT AUTO_INCREMENT PRIMARY KEY, + summarydate DATE NOT NULL, + machinenumber VARCHAR(20) NOT NULL, + updatecount INT DEFAULT 0, + uniqueoperators INT DEFAULT 0, + dateadded DATETIME DEFAULT CURRENT_TIMESTAMP, + UNIQUE INDEX uk_daily_machine_header (summarydate, machinenumber), + INDEX idx_summarydate (summarydate), + INDEX idx_machinenumber (machinenumber) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + -- ============================================================================ -- Stored Procedure: Summarize a specific date's data -- ============================================================================ @@ -126,6 +202,106 @@ BEGIN avg_deviation = VALUES(avg_deviation), max_deviation = VALUES(max_deviation), dateadded = CURRENT_TIMESTAMP; + + -- Summarize parts/production for the date + INSERT INTO udcpartsdaily + (summarydate, machinenumber, badgenumber, partscount, ootparts, totalmeasurements, totaloot, + avgcycletime, mincycletime, maxcycletime, avgchangeover) + SELECT + DATE(p.programstart) as summarydate, + s.machinenumber, + COALESCE(p.badgenumber, 'UNKNOWN') as badgenumber, + COUNT(*) as partscount, + SUM(CASE WHEN p.ootcount > 0 THEN 1 ELSE 0 END) as ootparts, + SUM(COALESCE(p.measurementcount, 0)) as totalmeasurements, + SUM(COALESCE(p.ootcount, 0)) as totaloot, + ROUND(AVG(p.cycletime), 2) as avgcycletime, + ROUND(MIN(p.cycletime), 2) as mincycletime, + ROUND(MAX(p.cycletime), 2) as maxcycletime, + ROUND(AVG(p.changeover), 2) as avgchangeover + FROM udcparts p + JOIN udcsessions s ON p.sessionid = s.sessionid + WHERE DATE(p.programstart) = p_date + GROUP BY DATE(p.programstart), s.machinenumber, COALESCE(p.badgenumber, 'UNKNOWN') + ON DUPLICATE KEY UPDATE + partscount = VALUES(partscount), + ootparts = VALUES(ootparts), + totalmeasurements = VALUES(totalmeasurements), + totaloot = VALUES(totaloot), + avgcycletime = VALUES(avgcycletime), + mincycletime = VALUES(mincycletime), + maxcycletime = VALUES(maxcycletime), + avgchangeover = VALUES(avgchangeover), + dateadded = CURRENT_TIMESTAMP; + + -- Summarize manual requests for the date + INSERT INTO udcmanualrequestsdaily + (summarydate, machinenumber, requestcount, avgresponseseconds, minresponseseconds, maxresponseseconds) + SELECT + DATE(mr.requesttime) as summarydate, + s.machinenumber, + COUNT(*) as requestcount, + ROUND(AVG(mr.responseseconds), 2) as avgresponseseconds, + ROUND(MIN(mr.responseseconds), 2) as minresponseseconds, + ROUND(MAX(mr.responseseconds), 2) as maxresponseseconds + FROM udcmanualrequests mr + JOIN udcparts p ON mr.partrunid = p.partrunid + JOIN udcsessions s ON p.sessionid = s.sessionid + WHERE DATE(mr.requesttime) = p_date + GROUP BY DATE(mr.requesttime), s.machinenumber + ON DUPLICATE KEY UPDATE + requestcount = VALUES(requestcount), + avgresponseseconds = VALUES(avgresponseseconds), + minresponseseconds = VALUES(minresponseseconds), + maxresponseseconds = VALUES(maxresponseseconds), + dateadded = CURRENT_TIMESTAMP; + + -- Summarize errors for the date + INSERT INTO udcerrorsdaily + (summarydate, machinenumber, errortype, errorcount) + SELECT + DATE(e.eventtime) as summarydate, + COALESCE(e.machinenumber, s.machinenumber) as machinenumber, + e.errortype, + COUNT(*) as errorcount + FROM udcerrors e + LEFT JOIN udcsessions s ON e.sessionid = s.sessionid + WHERE DATE(e.eventtime) = p_date + GROUP BY DATE(e.eventtime), COALESCE(e.machinenumber, s.machinenumber), e.errortype + ON DUPLICATE KEY UPDATE + errorcount = VALUES(errorcount), + dateadded = CURRENT_TIMESTAMP; + + -- Summarize violations for the date (CLM specific) + INSERT INTO udcviolationsdaily + (summarydate, machinenumber, badgenumber, violationcount) + SELECT + DATE(v.eventtime) as summarydate, + v.machinenumber, + COALESCE(v.badgenumber, 'UNKNOWN') as badgenumber, + COUNT(*) as violationcount + FROM udcviolations v + WHERE DATE(v.eventtime) = p_date + GROUP BY DATE(v.eventtime), v.machinenumber, COALESCE(v.badgenumber, 'UNKNOWN') + ON DUPLICATE KEY UPDATE + violationcount = VALUES(violationcount), + dateadded = CURRENT_TIMESTAMP; + + -- Summarize header updates for the date (badge changes) + INSERT INTO udcheaderupdatesdaily + (summarydate, machinenumber, updatecount, uniqueoperators) + SELECT + DATE(h.eventtime) as summarydate, + h.machinenumber, + COUNT(*) as updatecount, + COUNT(DISTINCT h.badgenumber) as uniqueoperators + FROM udcheaderupdates h + WHERE DATE(h.eventtime) = p_date + GROUP BY DATE(h.eventtime), h.machinenumber + ON DUPLICATE KEY UPDATE + updatecount = VALUES(updatecount), + uniqueoperators = VALUES(uniqueoperators), + dateadded = CURRENT_TIMESTAMP; END // DELIMITER ; @@ -300,6 +476,138 @@ SELECT FROM udctooldata_daily GROUP BY DATE_FORMAT(summarydate, '%Y-%m'), machinenumber, toolnumber; +-- Weekly parts/production trends from daily summaries +CREATE OR REPLACE VIEW vwudcparts_weekly AS +SELECT + YEARWEEK(summarydate, 1) as yearweek, + MIN(summarydate) as week_start, + machinenumber, + SUM(partscount) as partscount, + SUM(ootparts) as ootparts, + SUM(totalmeasurements) as totalmeasurements, + SUM(totaloot) as totaloot, + ROUND(AVG(avgcycletime), 2) as avgcycletime, + ROUND(AVG(avgchangeover), 2) as avgchangeover +FROM udcpartsdaily +GROUP BY YEARWEEK(summarydate, 1), machinenumber; + +-- Monthly parts/production trends from daily summaries +CREATE OR REPLACE VIEW vwudcparts_monthly AS +SELECT + DATE_FORMAT(summarydate, '%Y-%m') as yearmonth, + machinenumber, + SUM(partscount) as partscount, + SUM(ootparts) as ootparts, + SUM(totalmeasurements) as totalmeasurements, + SUM(totaloot) as totaloot, + ROUND(AVG(avgcycletime), 2) as avgcycletime, + ROUND(AVG(avgchangeover), 2) as avgchangeover +FROM udcpartsdaily +GROUP BY DATE_FORMAT(summarydate, '%Y-%m'), machinenumber; + +-- Weekly manual request trends from daily summaries +CREATE OR REPLACE VIEW vwudcmanualrequests_weekly AS +SELECT + YEARWEEK(summarydate, 1) as yearweek, + MIN(summarydate) as week_start, + machinenumber, + SUM(requestcount) as requestcount, + ROUND(AVG(avgresponseseconds), 2) as avgresponseseconds +FROM udcmanualrequestsdaily +GROUP BY YEARWEEK(summarydate, 1), machinenumber; + +-- Monthly manual request trends from daily summaries +CREATE OR REPLACE VIEW vwudcmanualrequests_monthly AS +SELECT + DATE_FORMAT(summarydate, '%Y-%m') as yearmonth, + machinenumber, + SUM(requestcount) as requestcount, + ROUND(AVG(avgresponseseconds), 2) as avgresponseseconds +FROM udcmanualrequestsdaily +GROUP BY DATE_FORMAT(summarydate, '%Y-%m'), machinenumber; + +-- Weekly error trends from daily summaries +CREATE OR REPLACE VIEW vwudcerrors_weekly AS +SELECT + YEARWEEK(summarydate, 1) as yearweek, + MIN(summarydate) as week_start, + machinenumber, + errortype, + SUM(errorcount) as errorcount +FROM udcerrorsdaily +GROUP BY YEARWEEK(summarydate, 1), machinenumber, errortype; + +-- Monthly error trends from daily summaries +CREATE OR REPLACE VIEW vwudcerrors_monthly AS +SELECT + DATE_FORMAT(summarydate, '%Y-%m') as yearmonth, + machinenumber, + errortype, + SUM(errorcount) as errorcount +FROM udcerrorsdaily +GROUP BY DATE_FORMAT(summarydate, '%Y-%m'), machinenumber, errortype; + +-- Weekly violation trends from daily summaries (CLM specific) +CREATE OR REPLACE VIEW vwudcviolations_weekly AS +SELECT + YEARWEEK(summarydate, 1) as yearweek, + MIN(summarydate) as week_start, + machinenumber, + SUM(violationcount) as violationcount +FROM udcviolationsdaily +GROUP BY YEARWEEK(summarydate, 1), machinenumber; + +-- Monthly violation trends from daily summaries (CLM specific) +CREATE OR REPLACE VIEW vwudcviolations_monthly AS +SELECT + DATE_FORMAT(summarydate, '%Y-%m') as yearmonth, + machinenumber, + SUM(violationcount) as violationcount +FROM udcviolationsdaily +GROUP BY DATE_FORMAT(summarydate, '%Y-%m'), machinenumber; + +-- Violations by operator (monthly) +CREATE OR REPLACE VIEW vwudcviolations_byoperator AS +SELECT + DATE_FORMAT(summarydate, '%Y-%m') as yearmonth, + machinenumber, + badgenumber, + SUM(violationcount) as violationcount +FROM udcviolationsdaily +GROUP BY DATE_FORMAT(summarydate, '%Y-%m'), machinenumber, badgenumber; + +-- Weekly header update trends from daily summaries (badge changes) +CREATE OR REPLACE VIEW vwudcheaderupdates_weekly AS +SELECT + YEARWEEK(summarydate, 1) as yearweek, + MIN(summarydate) as week_start, + machinenumber, + SUM(updatecount) as updatecount, + AVG(uniqueoperators) as avgoperators +FROM udcheaderupdatesdaily +GROUP BY YEARWEEK(summarydate, 1), machinenumber; + +-- Monthly header update trends from daily summaries (badge changes) +CREATE OR REPLACE VIEW vwudcheaderupdates_monthly AS +SELECT + DATE_FORMAT(summarydate, '%Y-%m') as yearmonth, + machinenumber, + SUM(updatecount) as updatecount, + AVG(uniqueoperators) as avgoperators +FROM udcheaderupdatesdaily +GROUP BY DATE_FORMAT(summarydate, '%Y-%m'), machinenumber; + +-- Monthly changeover time trends (from parts daily) +CREATE OR REPLACE VIEW vwudcchangeover_monthly AS +SELECT + DATE_FORMAT(summarydate, '%Y-%m') as yearmonth, + machinenumber, + ROUND(AVG(avgchangeover), 0) as avgchangeover, + SUM(partscount) as partscount +FROM udcpartsdaily +WHERE avgchangeover IS NOT NULL AND avgchangeover > 0 +GROUP BY DATE_FORMAT(summarydate, '%Y-%m'), machinenumber; + -- ============================================================================ -- Usage Instructions -- ============================================================================ diff --git a/updatelinkdirect.asp b/updatelinkdirect.asp index 8d46346..9706f33 100644 --- a/updatelinkdirect.asp +++ b/updatelinkdirect.asp @@ -51,6 +51,12 @@ If CLng(linkid) < 1 Then Response.End End If +If Len(linkurl) = 0 Or Len(shortdescription) = 0 Then + Response.Write("Required fields missing") + objConn.Close + Response.End +End If + If Len(linkurl) = 0 Or Len(shortdescription) = 0 Or Len(appid) = 0 Then Response.Write("Required fields missing") objConn.Close