Skip to content

Commit b80a886

Browse files
committed
Add list view for pipeline schedules
Signed-off-by: Keshav Priyadarshi <git@keshav.space>
1 parent f87771d commit b80a886

File tree

3 files changed

+177
-2
lines changed

3 files changed

+177
-2
lines changed

vulnerabilities/forms.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,16 @@ def clean_username(self):
8585

8686
def save_m2m(self):
8787
pass
88+
89+
90+
class PipelineSchedulePackageForm(forms.Form):
91+
search = forms.CharField(
92+
required=True,
93+
label=False,
94+
widget=forms.TextInput(
95+
attrs={
96+
"placeholder": "Search a pipeline...",
97+
"class": "input ",
98+
},
99+
),
100+
)
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
{% extends "base.html" %}
2+
3+
{% block title %}
4+
Pipeline Schedule
5+
{% endblock %}
6+
7+
{% block extrahead %}
8+
<style>
9+
thead th {
10+
border-bottom: none !important;
11+
}
12+
13+
tbody tr:hover {
14+
background-color: #e0e0e0 !important;
15+
cursor: pointer;
16+
}
17+
18+
tbody tr:nth-child(even):hover {
19+
background-color: #d3d3d3 !important;
20+
}
21+
22+
.column {
23+
word-break: break-word;
24+
}
25+
</style>
26+
{% endblock %}
27+
28+
29+
{% block content %}
30+
<div class="columns">
31+
<div class="column">
32+
</div>
33+
34+
<div class="column is-four-fifths">
35+
<div class="content is-normal">
36+
<h1>Pipeline Schedule</h1>
37+
<hr />
38+
</div>
39+
<form method="get" class="box px-6 mx-0" action="">
40+
<div class="field has-addons">
41+
<div class="control is-expanded">
42+
{{ form.search }}
43+
</div>
44+
<div class="control">
45+
<button type="submit" class="button is-info">Search</button>
46+
</div>
47+
</div>
48+
</form>
49+
<div class="box">
50+
<table class="table is-striped is-hoverable is-fullwidth">
51+
<thead>
52+
<tr>
53+
<th colspan="6">
54+
<div class="box is-small">
55+
<div class="columns is-mobile is-vcentered">
56+
<div class="column is-one-quarter">Pipeline ID</div>
57+
<div class="column is-one-eighth">Active</div>
58+
<div class="column is-one-eighth">Interval</div>
59+
<div class="column is-one-eighth">Status</div>
60+
<div class="column is-one-fifth">Latest Run</div>
61+
<div class="column is-one-fifth">Next Run</div>
62+
</div>
63+
</div>
64+
</th>
65+
</tr>
66+
</thead>
67+
<tbody>
68+
{% for schedule in schedule_list %}
69+
<tr>
70+
<td colspan="6">
71+
<a href="{% url 'runs-list' pipeline_id=schedule.pipeline_id %}" class="has-text-info">
72+
<div class="columns px-1 is-mobile is-vcentered">
73+
<div class="column is-one-quarter">{{ schedule.pipeline_id }}</div>
74+
<div class="column is-one-eighth">{{ schedule.is_active|yesno:"Yes,No" }}</div>
75+
<div class="column is-one-eighth">{{ schedule.run_interval }}day</div>
76+
<div class="column is-one-eighth">
77+
<span class="is-flex is-align-items-center">
78+
{% if schedule.status == "running" %}
79+
<span class="icon has-text-info mr-1"><i
80+
class="fa fa-spinner fa-spin"></i></span>
81+
<span>Running</span>
82+
{% elif schedule.status == "success" %}
83+
<span class="icon has-text-success mr-1"><i
84+
class="fa fa-check-circle"></i></span>
85+
<span>Success</span>
86+
{% elif schedule.status == "failure" %}
87+
<span class="icon has-text-danger mr-1"><i
88+
class="fa fa-times-circle"></i></span>
89+
<span>Failure</span>
90+
{% elif schedule.status == "scheduled" %}
91+
<span class="icon has-text-success mr-1"><i
92+
class="fa fa-clock-o"></i></span>
93+
<span>Scheduled</span>
94+
{% else %}
95+
<span class="icon has-text-warning mr-1"><i class="fa fa-question-circle"></i></span>
96+
<span>Unknown</span>
97+
{% endif %}
98+
</span>
99+
</div>
100+
101+
<div class="column is-one-fifth has-text-grey-light"
102+
title="{{ schedule.latest_run_date }}">
103+
{{ schedule.latest_run_date|date:"Y-m-d H:i" }}
104+
</div>
105+
<div class="column is-one-fifth has-text-grey-light"
106+
title="{{ schedule.next_run_date }}">
107+
{{ schedule.next_run_date|date:"Y-m-d" }}
108+
</div>
109+
110+
</div>
111+
</a>
112+
</td>
113+
</tr>
114+
{% empty %}
115+
<tr>
116+
<td colspan="6" class="has-text-centered">No pipeline found.</td>
117+
</tr>
118+
{% endfor %}
119+
</tbody>
120+
121+
</table>
122+
</div>
123+
{% if is_paginated %}
124+
<nav class="pagination is-centered px-5" role="navigation" aria-label="pagination">
125+
{% if page_obj.has_previous %}
126+
<a class="pagination-previous" href="?page={{ page_obj.previous_page_number }}">Previous</a>
127+
{% endif %}
128+
129+
{% if page_obj.has_next %}
130+
<a class="pagination-next" href="?page={{ page_obj.next_page_number }}">Next page</a>
131+
{% endif %}
132+
<ul class="pagination-list">
133+
<li><a class="pagination-link" aria-label="Goto page 1" href="?page=1">1</a></li>
134+
<li><span class="pagination-ellipsis">&hellip;</span></li>
135+
<li><a class="pagination-link" aria-label="Goto page {{ page_obj.number }}"
136+
href="?page={{ page_obj.paginator.num_pages }}">{{ page_obj.paginator.num_pages }}</a></li>
137+
</ul>
138+
</nav>
139+
{% endif %}
140+
</div>
141+
<div class="column"></div>
142+
</div>
143+
{% endblock %}

vulnerabilities/views.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,23 @@
1616
from django.core.mail import send_mail
1717
from django.db.models import Prefetch
1818
from django.http.response import Http404
19+
from django.shortcuts import get_object_or_404
1920
from django.shortcuts import redirect
2021
from django.shortcuts import render
2122
from django.urls import reverse_lazy
2223
from django.views import View
2324
from django.views import generic
2425
from django.views.generic.detail import DetailView
26+
from django.views.generic.edit import FormMixin
2527
from django.views.generic.list import ListView
26-
from univers.version_range import RANGE_CLASS_BY_SCHEMES
27-
from univers.version_range import AlpineLinuxVersionRange
2828

2929
from vulnerabilities import models
3030
from vulnerabilities.forms import ApiUserCreationForm
3131
from vulnerabilities.forms import PackageSearchForm
32+
from vulnerabilities.forms import PipelineSchedulePackageForm
3233
from vulnerabilities.forms import VulnerabilitySearchForm
34+
from vulnerabilities.models import PipelineRun
35+
from vulnerabilities.models import PipelineSchedule
3336
from vulnerabilities.severity_systems import EPSS
3437
from vulnerabilities.severity_systems import SCORING_SYSTEMS
3538
from vulnerablecode import __version__ as VULNERABLECODE_VERSION
@@ -346,3 +349,19 @@ def get_context_data(self, **kwargs):
346349
}
347350
)
348351
return context
352+
353+
354+
class PipelineScheduleListView(ListView, FormMixin):
355+
model = PipelineSchedule
356+
context_object_name = "schedule_list"
357+
template_name = "pipeline_schedule_list.html"
358+
paginate_by = 30
359+
form_class = PipelineSchedulePackageForm
360+
361+
def get_queryset(self):
362+
form = self.form_class(self.request.GET)
363+
if form.is_valid():
364+
return PipelineSchedule.objects.filter(
365+
pipeline_id__icontains=form.cleaned_data.get("search")
366+
)
367+
return PipelineSchedule.objects.all()

0 commit comments

Comments
 (0)