-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add filters in jobs status page #134
Merged
Merged
Changes from 13 commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
55065b6
feat: filter jobs by status
helen-m-lin ab658e7
feat: filter jobs by submit time window
helen-m-lin e2e1386
fix: sort jobs by submit time instead of start time
helen-m-lin 1a7705e
feat: display filters card at top
helen-m-lin ff3850b
feat: jobs filters styling
helen-m-lin eed3dcd
feat: custom range for submit time filters
helen-m-lin 4261e14
feat: only show jobs within last 2 weeks
helen-m-lin b7a40b3
refactor: jobs status page
helen-m-lin 0442525
feat: search by exact dag_run_id
helen-m-lin d9d1262
feat: collapsable filters
helen-m-lin c106402
test: unit tests for job filters
helen-m-lin 67ebe9e
refactor: run linters
helen-m-lin c10c167
refactor: code cleanup
helen-m-lin 850e00c
fix: datetime.fromisoformat for py<3.11
helen-m-lin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,8 +3,12 @@ | |
<head> | ||
<meta charset="UTF-8"> | ||
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"> | ||
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-icons/1.8.1/font/bootstrap-icons.min.css" rel="stylesheet"> | ||
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script> | ||
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.3/moment.min.js"></script> | ||
<script type="text/javascript" src="https://cdn.jsdelivr.net/jquery/latest/jquery.min.js"></script> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. imports for daterangepicker |
||
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.min.js"></script> | ||
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.css" /> | ||
<title>{% block title %} {% endblock %} AIND Data Transfer Service Jobs</title> | ||
<style> | ||
body { | ||
|
@@ -16,7 +20,7 @@ | |
} | ||
.content { | ||
width: 100%; | ||
height: calc(100vh - 200px); | ||
height: calc(100vh - 250px); | ||
iframe { | ||
border: none; | ||
width: 100%; | ||
|
@@ -35,7 +39,56 @@ | |
</nav> | ||
<div class="content"> | ||
<!-- display total entries from child iframe --> | ||
<h2 class="mb-3">Jobs Submitted: <span id="jobs-iframe-total-entries"></h2> | ||
<h2 class="mb-2">Jobs Submitted: <span id="jobs-iframe-total-entries"></h2> | ||
<!-- filters for job status results--> | ||
<div class="card mb-4" style="width:400px"> | ||
<div class="card-header py-1" type="button" data-bs-toggle="collapse" data-bs-target="#collapse-filters" aria-expanded="false" aria-controls="collapse-filters"> | ||
<i class="bi bi-filter"></i><span class="ms-2">Filter by</span> | ||
<i class="bi bi-chevron-expand float-end"></i> | ||
</div> | ||
<div id="collapse-filters" class="collapse card-body p-2"> | ||
<!-- filter by job status --> | ||
<div class="input-group input-group-sm mb-1"> | ||
<span class="input-group-text" style="width:35%">Status</span> | ||
<select class="form-select" onchange="filterJobsByStatus(this.value);this.blur();"> | ||
{% for s in [ | ||
{"label": "all", "value": [], "class": "text-dark"}, | ||
{"label": "queued", "value": ["queued"], "class": "text-secondary"}, | ||
{"label": "running", "value": ["running"], "class": "text-info"}, | ||
{"label": "failed", "value": ["failed"], "class": "text-danger"}, | ||
{"label": "success", "value": ["success"], "class": "text-success"}, | ||
] %} | ||
{% if s.value==default_state %}<option class="{{ s.class }}" value="{{ s.value }}" selected>{{ s.label }}</option> | ||
{% else %}<option class="{{ s.class }}" value="{{ s.value }}">{{ s.label }}</option> | ||
{% endif %} | ||
{% endfor %} | ||
</select> | ||
</div> | ||
<!-- filter by job submitted date range --> | ||
<div class="input-group input-group-sm"> | ||
<span class="input-group-text" style="width:35%">Submit Time</span> | ||
<input id="submit-date-range" class="form-select" type="text" /> | ||
</div> | ||
<!-- search by job id (exact match only) --> | ||
<div class="d-flex align-items-center"> | ||
<hr class="flex-grow-1 border-secondary"> | ||
<span class="mx-2"><small class="d-block">or</small></span> | ||
<hr class="flex-grow-1 border-secondary"> | ||
</div> | ||
<form onsubmit="searchByJobId(event)"> | ||
<div class="input-group input-group-sm"> | ||
<span class="input-group-text" style="width:35%">Job ID</span> | ||
<input id="job-id-input" type="text" class="form-control" placeholder="exact match only"> | ||
<button class="btn btn-outline-secondary" type="submit" title="Search"> | ||
<i class="bi bi-search"></i> | ||
</button> | ||
<button class="btn btn-outline-secondary" type="button" onclick="clearJobIdResult(event)" title="Clear"> | ||
<i class="bi bi-x-lg"></i> | ||
</button> | ||
</div> | ||
</form> | ||
</div> | ||
</div> | ||
<!-- toolbar to change jobs per page and navigate pages --> | ||
<div id="jobs-toolbar" class="btn-toolbar justify-content-between mb-2" role="toolbar"> | ||
<div class="input-group"> | ||
|
@@ -65,7 +118,7 @@ <h2 class="mb-3">Jobs Submitted: <span id="jobs-iframe-total-entries"></h2> | |
</div> | ||
</div> | ||
<!-- iframe to display paginated job status table --> | ||
<iframe id="jobs-iframe" src="{{ url_for('job_status_table').include_query_params(limit=default_limit, offset=default_offset)}}"></iframe> | ||
<iframe id="jobs-iframe" src=""></iframe> | ||
</div> | ||
<script> | ||
const PaginateTo = { | ||
|
@@ -74,12 +127,80 @@ <h2 class="mb-3">Jobs Submitted: <span id="jobs-iframe-total-entries"></h2> | |
FIRST: 'first', | ||
LAST: 'last' | ||
}; | ||
function updateJobStatusTableLimit(newLimit) { | ||
$(document).ready(function() { | ||
const today = moment(); | ||
const twoWeeksAgo = moment().subtract(13, 'days'); | ||
|
||
// initialize daterangepicker for submit date filter | ||
$('#submit-date-range').daterangepicker({ | ||
startDate: twoWeeksAgo, | ||
endDate: today, | ||
minDate: twoWeeksAgo, | ||
maxDate: today, | ||
ranges: { | ||
'Today': [today, today], | ||
'Last 3 Days': [moment().subtract(2, 'days'), today], | ||
'Last 7 Days': [moment().subtract(6, 'days'), today], | ||
'Last 14 Days': [twoWeeksAgo, today], | ||
} | ||
}, filterJobsBySubmitTimeRange); | ||
|
||
// initialize job status table with default values | ||
const initialParams = { | ||
limit: "{{ default_limit }}", | ||
offset: "{{ default_offset }}", | ||
state: "{{ default_state }}", | ||
// set default submit date range client-side for browser's local time | ||
execution_date_gte: twoWeeksAgo.startOf('day').toISOString(), | ||
execution_date_lte: today.endOf('day').toISOString(), | ||
}; | ||
updateJobStatusTable(initialParams, false, true); | ||
}); | ||
// EVENT HANDLERS ------------------------------------------------ | ||
function updateJobStatusTable(newParams, isSearchJobId=false, isInitial=false) { | ||
var iframe = document.getElementById('jobs-iframe'); | ||
var currentUrl = new URL(iframe.src); | ||
currentUrl.searchParams.set('limit', newLimit); | ||
var currentUrl = isInitial ? new URL("{{ url_for('job_status_table') }}") : new URL(iframe.src); | ||
Object.entries(newParams).forEach(([key, value]) => { | ||
currentUrl.searchParams.set(key, value); | ||
}); | ||
// reset job_id filter | ||
if (!isSearchJobId) { | ||
document.getElementById('job-id-input').value = ''; | ||
currentUrl.searchParams.delete('dag_run_id'); | ||
} | ||
iframe.src = currentUrl.toString(); | ||
} | ||
// Filters | ||
function filterJobsByStatus(newStatus) { | ||
updateJobStatusTable({ | ||
state: newStatus, | ||
offset: 0 // reset to first page | ||
}); | ||
} | ||
function filterJobsBySubmitTimeRange(start, end) { | ||
// NOTE: daterangepicker already has 00:00:00.000 and 23:59:59.999 for start and end | ||
updateJobStatusTable({ | ||
execution_date_gte: start.toISOString(), | ||
execution_date_lte: end.toISOString(), | ||
offset: 0 // reset to first page | ||
}); | ||
} | ||
function searchByJobId(event) { | ||
event.preventDefault(); | ||
// search by job id and reset to first page | ||
const jobId = document.getElementById('job-id-input').value; | ||
console.log('Searching for job ID:', jobId); | ||
updateJobStatusTable({ dag_run_id: jobId, offset: 0}, true); | ||
} | ||
function clearJobIdResult(event) { | ||
event.preventDefault(); | ||
// clear job id filter and reset to first page | ||
updateJobStatusTable({ offset: 0 }, false); | ||
} | ||
// Pagination | ||
function updateJobStatusTableLimit(newLimit) { | ||
updateJobStatusTable({limit: newLimit}); | ||
} | ||
function updateJobStatusTablePage(paginateTo) { | ||
var iframe = document.getElementById('jobs-iframe'); | ||
var currentUrl = new URL(iframe.src); | ||
|
@@ -101,8 +222,7 @@ <h2 class="mb-3">Jobs Submitted: <span id="jobs-iframe-total-entries"></h2> | |
offset = Math.floor(totalEntries / limit) * limit; | ||
break; | ||
} | ||
currentUrl.searchParams.set('offset', offset); | ||
iframe.src = currentUrl.toString(); | ||
updateJobStatusTable({offset: offset}); | ||
} | ||
</script> | ||
</body> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated
order_by
to sort results by submit time (previously start time) for consistency