feat: v1.5.8 - bucket Awaiting Vendor and Awaiting Parts into sidebar lists

This commit is contained in:
2026-06-15 14:50:29 +10:00
parent 0a7add579b
commit 1226bb001d
+9 -24
View File
@@ -9,7 +9,7 @@ namespace Disco.Plugins.ServiceTracker.Services
{ {
public class ServiceTrackerService public class ServiceTrackerService
{ {
public const string PluginVersion = "1.5.7"; public const string PluginVersion = "1.5.8";
/// <summary> /// <summary>
/// Status values that mean a ticket is closed/done. Checked against the saved StatusOverride /// Status values that mean a ticket is closed/done. Checked against the saved StatusOverride
@@ -70,7 +70,9 @@ namespace Disco.Plugins.ServiceTracker.Services
} }
var rfr = tiles.Where(t => { var s = (t.StatusOverride ?? t.DiscoStatus ?? "").ToLower(); return s.Contains("ready for return") || s.Contains("ready for pickup"); }).ToList(); var rfr = tiles.Where(t => { var s = (t.StatusOverride ?? t.DiscoStatus ?? "").ToLower(); return s.Contains("ready for return") || s.Contains("ready for pickup"); }).ToList();
var onHold = tiles.Where(t => { var s = (t.StatusOverride ?? t.DiscoStatus ?? "").ToLower(); return s.Contains("on hold") && !rfr.Contains(t); }).ToList(); var onHold = tiles.Where(t => { var s = (t.StatusOverride ?? t.DiscoStatus ?? "").ToLower(); return s.Contains("on hold") && !rfr.Contains(t); }).ToList();
var main = tiles.Where(t => !rfr.Contains(t) && !onHold.Contains(t)).ToList(); var awaitingVendor = tiles.Where(t => { var s = (t.StatusOverride ?? t.DiscoStatus ?? "").ToLower(); return s.Contains("awaiting vendor") && !rfr.Contains(t) && !onHold.Contains(t); }).ToList();
var awaitingParts = tiles.Where(t => { var s = (t.StatusOverride ?? t.DiscoStatus ?? "").ToLower(); return s.Contains("awaiting parts") && !rfr.Contains(t) && !onHold.Contains(t) && !awaitingVendor.Contains(t); }).ToList();
var main = tiles.Where(t => !rfr.Contains(t) && !onHold.Contains(t) && !awaitingVendor.Contains(t) && !awaitingParts.Contains(t)).ToList();
if (!string.IsNullOrEmpty(filterPriority)) main = main.Where(t => t.PriorityId == filterPriority).ToList(); if (!string.IsNullOrEmpty(filterPriority)) main = main.Where(t => t.PriorityId == filterPriority).ToList();
if (!string.IsNullOrEmpty(filterLocation)) main = main.Where(t => t.LocationId == filterLocation).ToList(); if (!string.IsNullOrEmpty(filterLocation)) main = main.Where(t => t.LocationId == filterLocation).ToList();
if (!string.IsNullOrEmpty(filterStatus)) main = main.Where(t => t.StatusOverride == filterStatus).ToList(); if (!string.IsNullOrEmpty(filterStatus)) main = main.Where(t => t.StatusOverride == filterStatus).ToList();
@@ -85,7 +87,7 @@ namespace Disco.Plugins.ServiceTracker.Services
case "newest": default: main = main.OrderByDescending(t => t.OpenedDate).ToList(); break; case "newest": default: main = main.OrderByDescending(t => t.OpenedDate).ToList(); break;
} }
var stats = BuildStats(main); stats.FromGoogleSheet = sheetCount; var stats = BuildStats(main); stats.FromGoogleSheet = sheetCount;
var result = new DashboardViewModel { Tiles = main, ReadyForReturn = rfr, OnHold = onHold, Stats = stats, Config = _config, CurrentFilter = filterPriority ?? filterLocation ?? filterStatus ?? "", SortBy = sortBy, GoogleSheetError = sheetError }; var result = new DashboardViewModel { Tiles = main, ReadyForReturn = rfr, OnHold = onHold, AwaitingVendor = awaitingVendor, AwaitingParts = awaitingParts, Stats = stats, Config = _config, CurrentFilter = filterPriority ?? filterLocation ?? filterStatus ?? "", SortBy = sortBy, GoogleSheetError = sheetError };
// --- Store in cache --- // --- Store in cache ---
DashboardCache.Store(result, _dataStore.DataDirectory, sortBy, filterKey); DashboardCache.Store(result, _dataStore.DataDirectory, sortBy, filterKey);
@@ -120,8 +122,6 @@ namespace Disco.Plugins.ServiceTracker.Services
var pid = st != null ? st.PriorityId : GoogleSheetService.MapPriority(ext.RawPriority); var pid = st != null ? st.PriorityId : GoogleSheetService.MapPriority(ext.RawPriority);
var pri = _config.Priorities.FirstOrDefault(p => p.Id == pid) ?? _config.Priorities.FirstOrDefault(); var pri = _config.Priorities.FirstOrDefault(p => p.Id == pid) ?? _config.Priorities.FirstOrDefault();
// Location resolution: prefer saved override; otherwise try to match the raw sheet location text
// against configured locations; fall back to default if nothing matches.
var lid = st != null ? st.LocationId : null; var lid = st != null ? st.LocationId : null;
string rawSheetLocation = null; string rawSheetLocation = null;
if (string.IsNullOrEmpty(lid) && !string.IsNullOrEmpty(ext.Location)) if (string.IsNullOrEmpty(lid) && !string.IsNullOrEmpty(ext.Location))
@@ -130,7 +130,7 @@ namespace Disco.Plugins.ServiceTracker.Services
if (matched != null) if (matched != null)
lid = matched.Id; lid = matched.Id;
else else
rawSheetLocation = ext.Location; // unmatched - store for display rawSheetLocation = ext.Location;
} }
if (string.IsNullOrEmpty(lid)) lid = _config.DefaultLocationId; if (string.IsNullOrEmpty(lid)) lid = _config.DefaultLocationId;
var loc = _config.Locations.FirstOrDefault(l => l.Id == lid) ?? _config.Locations.FirstOrDefault(); var loc = _config.Locations.FirstOrDefault(l => l.Id == lid) ?? _config.Locations.FirstOrDefault();
@@ -144,28 +144,13 @@ namespace Disco.Plugins.ServiceTracker.Services
return new DashboardTile { JobId = ext.InternalId, Source = "ntt", DisplayId = "NTT#" + ext.InternalId, JobTypeDescription = "NTT Sheet", DeviceSerialNumber = ext.TaskTitle ?? "\u2014", DeviceComputerName = ext.TaskTitle, UserId = ext.RequesterEmail, UserDisplayName = rn, OpenedDate = ext.Timestamp, DiscoStatus = ext.RawStatus ?? "Open", PriorityId = pid, PriorityName = pri != null ? pri.Name : "Unknown", PriorityColor = pri != null ? pri.Color : "#999", PrioritySortOrder = pri != null ? pri.SortOrder : 99, LocationId = lid, LocationName = loc != null ? loc.Name : "Unknown", LocationIcon = loc != null ? loc.Icon : "", LocationColor = loc != null ? loc.Color : "#999", RawSheetLocation = rawSheetLocation, AssignedTechId = tid, AssignedTechName = ResolveTechName(tid), StatusOverride = st != null && st.StatusOverride != null ? st.StatusOverride : (ext.RawStatus ?? "Open"), Summary = ext.IssueDescription, EstimatedCompletion = ext.PreferredDate, NoteCount = nc, LatestNote = ln, LastModifiedDate = st != null ? st.LastModifiedDate : ext.Timestamp, AgeBadge = FmtAge(age), AgeDays = age, EtaDisplay = FmtEta(st != null && st.EstimatedCompletion.HasValue ? st.EstimatedCompletion : ext.PreferredDate), SortDate = st != null && st.EstimatedCompletion.HasValue ? st.EstimatedCompletion.Value : ext.PreferredDate.HasValue ? ext.PreferredDate.Value : ext.Timestamp }; return new DashboardTile { JobId = ext.InternalId, Source = "ntt", DisplayId = "NTT#" + ext.InternalId, JobTypeDescription = "NTT Sheet", DeviceSerialNumber = ext.TaskTitle ?? "\u2014", DeviceComputerName = ext.TaskTitle, UserId = ext.RequesterEmail, UserDisplayName = rn, OpenedDate = ext.Timestamp, DiscoStatus = ext.RawStatus ?? "Open", PriorityId = pid, PriorityName = pri != null ? pri.Name : "Unknown", PriorityColor = pri != null ? pri.Color : "#999", PrioritySortOrder = pri != null ? pri.SortOrder : 99, LocationId = lid, LocationName = loc != null ? loc.Name : "Unknown", LocationIcon = loc != null ? loc.Icon : "", LocationColor = loc != null ? loc.Color : "#999", RawSheetLocation = rawSheetLocation, AssignedTechId = tid, AssignedTechName = ResolveTechName(tid), StatusOverride = st != null && st.StatusOverride != null ? st.StatusOverride : (ext.RawStatus ?? "Open"), Summary = ext.IssueDescription, EstimatedCompletion = ext.PreferredDate, NoteCount = nc, LatestNote = ln, LastModifiedDate = st != null ? st.LastModifiedDate : ext.Timestamp, AgeBadge = FmtAge(age), AgeDays = age, EtaDisplay = FmtEta(st != null && st.EstimatedCompletion.HasValue ? st.EstimatedCompletion : ext.PreferredDate), SortDate = st != null && st.EstimatedCompletion.HasValue ? st.EstimatedCompletion.Value : ext.PreferredDate.HasValue ? ext.PreferredDate.Value : ext.Timestamp };
} }
/// <summary>
/// Tries to match a raw location string from the Google Sheet against the configured Disco locations.
/// Checks: exact ID match, exact name match (case-insensitive), name contains raw text, raw text contains name.
/// Returns the matched DeviceLocation, or null if no match found.
/// </summary>
private DeviceLocation MatchSheetLocation(string raw) private DeviceLocation MatchSheetLocation(string raw)
{ {
if (string.IsNullOrEmpty(raw)) return null; if (string.IsNullOrEmpty(raw)) return null;
var lower = raw.Trim().ToLower(); var lower = raw.Trim().ToLower();
foreach (var loc in _config.Locations) foreach (var loc in _config.Locations) { if (loc.Id.Equals(lower, StringComparison.OrdinalIgnoreCase)) return loc; }
{ foreach (var loc in _config.Locations) { if (loc.Name.Equals(lower, StringComparison.OrdinalIgnoreCase)) return loc; }
if (loc.Id.Equals(lower, StringComparison.OrdinalIgnoreCase)) return loc; foreach (var loc in _config.Locations) { var locLower = loc.Name.ToLower(); if (locLower.Contains(lower) || lower.Contains(locLower)) return loc; }
}
foreach (var loc in _config.Locations)
{
if (loc.Name.Equals(lower, StringComparison.OrdinalIgnoreCase)) return loc;
}
foreach (var loc in _config.Locations)
{
var locLower = loc.Name.ToLower();
if (locLower.Contains(lower) || lower.Contains(locLower)) return loc;
}
return null; return null;
} }