forked from GithubBackups/healthchecks
Show overall project status in the top navigation menu and in the "Select Project" page. cc: #183
This commit is contained in:
parent
886643db84
commit
62310a5181
@ -8,6 +8,7 @@ from django.contrib.auth.hashers import check_password, make_password
|
|||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core.signing import TimestampSigner
|
from django.core.signing import TimestampSigner
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.db.models import Count, Q
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from hc.lib import emails
|
from hc.lib import emails
|
||||||
@ -113,11 +114,21 @@ class Profile(models.Model):
|
|||||||
def projects(self):
|
def projects(self):
|
||||||
""" Return a queryset of all projects we have access to. """
|
""" Return a queryset of all projects we have access to. """
|
||||||
|
|
||||||
is_owner = models.Q(owner=self.user)
|
is_owner = Q(owner=self.user)
|
||||||
is_member = models.Q(member__user=self.user)
|
is_member = Q(member__user=self.user)
|
||||||
q = Project.objects.filter(is_owner | is_member)
|
q = Project.objects.filter(is_owner | is_member)
|
||||||
return q.distinct().order_by("name")
|
return q.distinct().order_by("name")
|
||||||
|
|
||||||
|
def annotated_projects(self):
|
||||||
|
""" Return all projects, annotated with 'n_down'. """
|
||||||
|
|
||||||
|
is_owner = Q(owner=self.user)
|
||||||
|
is_member = Q(member__user=self.user)
|
||||||
|
q = Project.objects.filter(is_owner | is_member)
|
||||||
|
n_down = Count("check", filter=Q(check__status="down"))
|
||||||
|
q = q.annotate(n_down=n_down)
|
||||||
|
return q.distinct().order_by("name")
|
||||||
|
|
||||||
def checks_from_all_projects(self):
|
def checks_from_all_projects(self):
|
||||||
""" Return a queryset of checks from projects we have access to. """
|
""" Return a queryset of checks from projects we have access to. """
|
||||||
|
|
||||||
@ -236,8 +247,8 @@ class Project(models.Model):
|
|||||||
def set_next_nag_date(self):
|
def set_next_nag_date(self):
|
||||||
""" Set next_nag_date on profiles of all members of this project. """
|
""" Set next_nag_date on profiles of all members of this project. """
|
||||||
|
|
||||||
is_owner = models.Q(user=self.owner)
|
is_owner = Q(user=self.owner)
|
||||||
is_member = models.Q(user__memberships__project=self)
|
is_member = Q(user__memberships__project=self)
|
||||||
q = Profile.objects.filter(is_owner | is_member)
|
q = Profile.objects.filter(is_owner | is_member)
|
||||||
q = q.exclude(nag_period=NO_NAG)
|
q = q.exclude(nag_period=NO_NAG)
|
||||||
# Exclude profiles with next_nag_date already set
|
# Exclude profiles with next_nag_date already set
|
||||||
|
@ -307,8 +307,8 @@ def project(request, code):
|
|||||||
project.name = form.cleaned_data["name"]
|
project.name = form.cleaned_data["name"]
|
||||||
project.save()
|
project.save()
|
||||||
|
|
||||||
if request.project.id == project.id:
|
if request.profile.current_project == project:
|
||||||
request.project = project
|
request.profile.current_project.name = project.name
|
||||||
|
|
||||||
ctx["project_name_updated"] = True
|
ctx["project_name_updated"] = True
|
||||||
ctx["project_name_status"] = "success"
|
ctx["project_name_status"] = "success"
|
||||||
|
@ -195,7 +195,7 @@ def switch_channel(request, code, channel_code):
|
|||||||
|
|
||||||
def index(request):
|
def index(request):
|
||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
projects = list(request.profile.projects())
|
projects = list(request.profile.annotated_projects())
|
||||||
|
|
||||||
if len(projects) == 1:
|
if len(projects) == 1:
|
||||||
return redirect("hc-checks", projects[0].code)
|
return redirect("hc-checks", projects[0].code)
|
||||||
|
@ -111,3 +111,7 @@ pre {
|
|||||||
font-size: small;
|
font-size: small;
|
||||||
padding: 2px 0;
|
padding: 2px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.badge-down {
|
||||||
|
background-color: #d9534f;
|
||||||
|
}
|
||||||
|
@ -12,23 +12,19 @@
|
|||||||
|
|
||||||
#project-selector .project {
|
#project-selector .project {
|
||||||
border-color: #ddd;
|
border-color: #ddd;
|
||||||
padding: 24px;
|
padding: 24px 24px 24px 64px;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#project-selector .project h4 {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
#project-selector .project.selected {
|
#project-selector .project.selected {
|
||||||
border-color: #0091EA;
|
border-color: #0091EA;
|
||||||
}
|
}
|
||||||
|
|
||||||
#project-selector .project.selected .marker {
|
#project-selector .project .status {
|
||||||
display: block;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
left: 24px;
|
||||||
font-size: 10px;
|
}
|
||||||
padding: 2px 8px;
|
|
||||||
border-bottom-left-radius: 3px;
|
|
||||||
border-bottom-right-radius: 3px;
|
|
||||||
color: #fff;
|
|
||||||
background: #0091EA;
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
@ -116,6 +116,7 @@
|
|||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
<li class="dropdown">
|
<li class="dropdown">
|
||||||
<a id="nav-email" href="#" class="dropdown-toggle" data-toggle="dropdown" role="button">
|
<a id="nav-email" href="#" class="dropdown-toggle" data-toggle="dropdown" role="button">
|
||||||
|
|
||||||
{% if check %}
|
{% if check %}
|
||||||
{{ check.project }}
|
{{ check.project }}
|
||||||
{% elif request.profile.current_project %}
|
{% elif request.profile.current_project %}
|
||||||
@ -123,15 +124,23 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
{{ request.user.email }}
|
{{ request.user.email }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<span class="caret"></span>
|
<span class="caret"></span>
|
||||||
</a>
|
</a>
|
||||||
<ul class="dropdown-menu">
|
<ul class="dropdown-menu">
|
||||||
{% for project in request.profile.projects.all %}
|
{% for project in request.profile.annotated_projects %}
|
||||||
<li class="dropdown-header">{{ project }}</li>
|
<li class="dropdown-header">{{ project }}</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url 'hc-checks' project.code %}">Checks</a>
|
<a href="{% url 'hc-checks' project.code %}">
|
||||||
|
Checks
|
||||||
|
{% if project.n_down %}
|
||||||
|
<span class="badge badge-down pull-right">
|
||||||
|
{{ project.n_down }}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% if project.owner == request.user %}
|
{% if project.owner_id == request.user.id %}
|
||||||
<li>
|
<li>
|
||||||
<a href="{% url 'hc-project-settings' project.code %}">Project Settings</a>
|
<a href="{% url 'hc-project-settings' project.code %}">Project Settings</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -19,15 +19,18 @@
|
|||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<div id="project-selector" class="row">
|
<div id="project-selector" class="row">
|
||||||
{% for project in projects%}
|
{% for project in projects %}
|
||||||
<a href="{% url 'hc-checks' project.code %}">
|
<a href="{% url 'hc-checks' project.code %}">
|
||||||
<div class="col-sm-6 col-md-4">
|
<div class="col-sm-6 col-md-4">
|
||||||
<div class="panel project {% if project == request.profile.current_project %}selected{% endif %}">
|
<div class="panel project {% if project == request.profile.current_project %}selected{% endif %}">
|
||||||
{% if project == request.profile.current_project %}
|
{% if project.n_down %}
|
||||||
<div class="marker">Current Project</div>
|
<div class="status icon-down"></div>
|
||||||
|
{% else %}
|
||||||
|
<div class="status icon-up"></div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
<h4>{{ project }}</h4>
|
<h4>{{ project }}</h4>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
{% with project.check_set.count as n %}
|
{% with project.check_set.count as n %}
|
||||||
{{ n }} check{{ n|pluralize }},
|
{{ n }} check{{ n|pluralize }},
|
||||||
@ -40,6 +43,7 @@
|
|||||||
<div class="text-muted">
|
<div class="text-muted">
|
||||||
{{ project.owner.email }}
|
{{ project.owner.email }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user