Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions Components/Pages/Jobs.razor
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,14 @@
<option value="not-estimated">Exclude Estimated</option>
</select>
</div>
<div class="col-md-2">
<label class="form-label" for="filter-description">Description</label>
<select id="filter-description" class="form-select" @bind="selectedNeedsDescription" @bind:after="ApplyFilter" aria-label="Filter by description status">
<option value="">All</option>
<option value="true">Needs Description</option>
<option value="false">Has Description</option>
</select>
</div>
<div class="col-md-2">
<label class="form-label" for="filter-title">Title Only</label>
<input type="text" id="filter-title" class="form-control" placeholder="Search job title only..."
Expand Down Expand Up @@ -2688,6 +2696,7 @@ else
private string selectedInterest = "";
private string selectedScoreBand = "";
private string selectedHasSalary = "";
private string selectedNeedsDescription = "";
private string selectedApplicationStage = "";
private string selectedSource = "";
private string selectedIsAgency = "";
Expand Down Expand Up @@ -2928,6 +2937,7 @@ else
filter.Interest = string.IsNullOrEmpty(selectedInterest) ? null : Enum.Parse<InterestStatus>(selectedInterest);
filter.HasSalary = selectedHasSalary == "true" ? true : selectedHasSalary == "false" ? false : null;
filter.SalarySourceFilter = selectedHasSalary == "posted" || selectedHasSalary == "estimated" || selectedHasSalary == "not-estimated" ? selectedHasSalary : null;
filter.NeedsDescription = selectedNeedsDescription == "true" ? true : selectedNeedsDescription == "false" ? false : null;
filter.ApplicationStage = string.IsNullOrEmpty(selectedApplicationStage) ? null : Enum.Parse<ApplicationStage>(selectedApplicationStage);
Comment on lines 2937 to 2941
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

selectedNeedsDescription is now part of the active filter state (filter.NeedsDescription), but it isn’t included in the filter preset save/restore logic (SaveCurrentAsPreset / OnPresetSelected). This means presets won’t persist the new Description filter selection. Consider extending SavedFilterPreset and updating preset save/restore to include this field for consistent behavior with the other filter controls.

Copilot uses AI. Check for mistakes.
filter.Source = string.IsNullOrEmpty(selectedSource) ? null : selectedSource;
filter.IsAgency = string.IsNullOrEmpty(selectedIsAgency) ? null : bool.Parse(selectedIsAgency);
Expand Down Expand Up @@ -2978,6 +2988,7 @@ else
selectedInterest = "";
selectedScoreBand = "";
selectedHasSalary = "";
selectedNeedsDescription = "";
selectedApplicationStage = "";
selectedSource = "";
selectedIsAgency = "";
Expand Down Expand Up @@ -4318,6 +4329,7 @@ else
Interest = selectedInterest,
ScoreBand = selectedScoreBand,
HasSalary = selectedHasSalary,
NeedsDescription = selectedNeedsDescription,
SalarySearch = filter.SalarySearch,
SalaryTarget = selectedSalaryTarget,
SalaryType = selectedSalaryType,
Expand Down Expand Up @@ -4350,6 +4362,7 @@ else
selectedInterest = vs.Interest ?? "";
selectedScoreBand = vs.ScoreBand ?? "";
selectedHasSalary = vs.HasSalary ?? "";
selectedNeedsDescription = vs.NeedsDescription ?? "";
selectedSalaryTarget = vs.SalaryTarget ?? "";
selectedSalaryType = vs.SalaryType ?? "";
selectedSource = vs.Source ?? "";
Expand Down
1 change: 1 addition & 0 deletions Models/AppSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ public class JobViewState
public string? Interest { get; set; }
public string? ScoreBand { get; set; }
public string? HasSalary { get; set; }
public string? NeedsDescription { get; set; }
public string? SalarySearch { get; set; }
public string? SalaryTarget { get; set; }
public string? SalaryType { get; set; }
Expand Down
2 changes: 1 addition & 1 deletion Portable/JobTracker-x64.zip.001
Git LFS file not shown
4 changes: 2 additions & 2 deletions Portable/JobTracker-x64.zip.002
Git LFS file not shown
2 changes: 1 addition & 1 deletion Portable/JobTracker-x86.zip.001
Git LFS file not shown
4 changes: 2 additions & 2 deletions Portable/JobTracker-x86.zip.002
Git LFS file not shown
10 changes: 10 additions & 0 deletions Services/JobListingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2280,6 +2280,15 @@ public IEnumerable<JobListing> FilterJobListings(JobListingFilter filter)
query = query.Where(j => j.Skills != null && j.Skills.Any(s => s.Contains(skillTerm, StringComparison.OrdinalIgnoreCase)));
}

// Needs description filter
if (filter.NeedsDescription.HasValue)
{
if (filter.NeedsDescription.Value)
query = query.Where(j => string.IsNullOrWhiteSpace(j.Description));
else
query = query.Where(j => !string.IsNullOrWhiteSpace(j.Description));
Comment on lines +2283 to +2289
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new NeedsDescription filter only checks for an empty/whitespace Description, but elsewhere in this service “needs description” is defined as empty OR very short (e.g., < 100 chars in UpdateJobDescription, GetJobsNeedingDescriptions, and stats). This makes the UI filter inconsistent with the existing badge/API and will miss jobs that have a stub description. Consider using the same predicate here (including the length threshold) and reusing it for both the true and false branches to keep behavior consistent.

Suggested change
// Needs description filter
if (filter.NeedsDescription.HasValue)
{
if (filter.NeedsDescription.Value)
query = query.Where(j => string.IsNullOrWhiteSpace(j.Description));
else
query = query.Where(j => !string.IsNullOrWhiteSpace(j.Description));
const int MinimumDescriptionLength = 100;
bool NeedsDescription(JobListing job) =>
string.IsNullOrWhiteSpace(job.Description) ||
job.Description.Trim().Length < MinimumDescriptionLength;
// Needs description filter
if (filter.NeedsDescription.HasValue)
{
if (filter.NeedsDescription.Value)
query = query.Where(NeedsDescription);
else
query = query.Where(j => !NeedsDescription(j));

Copilot uses AI. Check for mistakes.
}

// Sort order:
// 1. Prioritized job first (if specified)
// 2. Applied jobs next
Expand Down Expand Up @@ -3100,6 +3109,7 @@ public class JobListingFilter
public bool? IsAgency { get; set; }
public bool ShowArchived { get; set; }
public List<string>? SkillPriorities { get; set; }
public bool? NeedsDescription { get; set; }
}

public enum SortOption
Expand Down
Loading