Skip to content
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

Adds credential application tracker to admin console #1250

Open
wants to merge 2 commits into
base: dev
Choose a base branch
from
Open
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
27 changes: 27 additions & 0 deletions physionet-django/console/static/console/css/console.css
Original file line number Diff line number Diff line change
Expand Up @@ -531,15 +531,42 @@ footer.sticky-footer {
table-layout: fixed;
width: 100%;
}

.table-index {
width: 5%;
}

.table-user {
width: 10%;
}

.table-elapsed {
width: 9%;
}

.table-process {
width: 11%;
}

.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}

.grid path,
.grid line {
fill: none;
stroke: rgba(0, 0, 0, 0.25);
shape-rendering: crispEdges;
}

.x.axis path {
display: none;
}

.line {
fill: none;
stroke-width: 2.5px;
}
144 changes: 144 additions & 0 deletions physionet-django/console/static/console/js/console.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,147 @@
event.preventDefault();
});
})(jQuery); // End of use strict

// Define the chart (try to make dynamic)
var cred_chart = d3_cred_chart()
.width(0.845 * window.innerWidth)
.height(0.7 * window.innerHeight)
.x_label("Date")
.y_label("Pending Applications");
// Define the canvas
var svg = d3.select("#cred_tracker").append("svg")
.datum(data)
.call(cred_chart);
// Create the figure
function d3_cred_chart() {
// Actually edit the chart
function chart(selection){
selection.each(function(input_data) {
// Set the margins
var margin = {top: 20, right: 80, bottom: 80, left: 100},
inner_width = width - margin.left - margin.right,
inner_height = height - margin.top - margin.bottom;
// Parse the input dates
var parse_time = d3.time.format("%d-%b-%y").parse;
input_data[0].x.forEach(function(d,i){
input_data[0].x[i] = parse_time(d);
});
// Set the x-axis scale
var x_scale = d3.time.scale()
.range([0, inner_width])
.domain([d3.min(input_data, function(d) { return d3.min(d.x); }),
d3.max(input_data, function(d) { return d3.max(d.x); })]);
// Set the y-axis scale
var y_scale = d3.scale.linear()
.range([inner_height, 0])
.domain([0,
d3.max(input_data, function(d) { return 1.1*d3.max(d.y); })]);
// Define the x-axis
var x_axis = d3.svg.axis()
.scale(x_scale)
.orient("bottom")
.tickFormat(d3.time.format("%d-%b-%y"));
// Define the y-axis
var y_axis = d3.svg.axis()
.scale(y_scale)
.orient("left");
// Set the x-axis grid
var x_grid = d3.svg.axis()
.scale(x_scale)
.orient("bottom")
.tickSize(-inner_height)
.tickFormat("");
// Set the y-axis grid
var y_grid = d3.svg.axis()
.scale(y_scale)
.orient("left")
.tickSize(-inner_width)
.tickFormat("");
// Draw the actual line
var draw_line = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x_scale(d[0]); })
.y(function(d) { return y_scale(d[1]); });
// Create the SVG object
var svg = d3.select(this)
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Set the inner padding for the x-axis
svg.append("g")
.attr("class", "x grid")
.attr("transform", "translate(0," + inner_height + ")")
.call(x_grid);
// Set the inner padding for the y-axis
svg.append("g")
.attr("class", "y grid")
.call(y_grid);
// Set the x-label
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + inner_height + ")")
.call(x_axis)
.selectAll("text")
.style("text-anchor", "middle")
.attr("dx", "-2.5em")
.attr("dy", "0.7em")
.attr("transform", function(d) {
return "rotate(-45)"
})
// Set the y-label
svg.append("g")
.attr("class", "y axis")
.call(y_axis)
.append("text")
.attr("transform", "translate(0," + inner_height/2 + ")rotate(-90)")
.attr("dy", "-4em")
.attr('text-anchor', 'middle')
.text(y_label);
// Get the line data
var data_lines = svg.selectAll(".d3_cred_chart_line")
.data(input_data.map(function(d) { return d3.zip(d.x, d.y); }))
.enter().append("g")
.attr("class", "d3_cred_chart_line");
// Draw the line and set the color
data_lines.append("path")
.attr("class", "line")
.attr("d", function(d){ return draw_line(d); })
.attr("stroke", "red");
});
};
// Set the canvas width
chart.width = function(value) {
if (!arguments.length) {
return width;
};
width = value;
return chart;
};
// Set the canvas height
chart.height = function(value) {
if (!arguments.length) {
return height;
};
height = value;
return chart;
};
// Set the x-label
chart.x_label = function(value) {
if (!arguments.length) {
return x_label;
};
x_label = value;
return chart;
};
// Set the y-label
chart.y_label = function(value) {
if (!arguments.length) {
return y_label;
};
y_label = value;
return chart;
};
// Render the figure
return chart;
};
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,9 @@
<li class="nav-item {% if submenu == 'credential' %}active{% endif %}">
<a href="{% url 'credentialing_stats' %}">Credentialing</a>
</li>
<li class="nav-item {% if submenu == 'graph' %}active{% endif %}">
<a href="{% url 'graph_stats' %}">Graphs</a>
</li>
</ul>
</li>

Expand Down
36 changes: 36 additions & 0 deletions physionet-django/console/templates/console/graph_stats.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{% extends "console/base_console.html" %}

{% load static %}

{% block title %}Graphs{% endblock %}

{% block local_js_top %}
<script type="text/javascript">
// Define the data
var data = [{
x: "{{ timeline }}".split(','),
y: {{ net_apps }}
}];
</script>
<script src="{% static 'd3/d3.v3.min.js' %}"></script>
<script src="{% static 'd3/d3.tip.v0.6.3.js' %}"></script>
<script src="{% static 'console/js/console.js' %}"></script>
{% endblock %}

{% block content %}

<div class="card mb-3">
<div class="card-header">
Graph metrics
</div>
<div id="cred_tracker">
<div class="card-body">
<h1>Previous Credentialing Applications</h1>
<section class="indented-box">
<p>This graph displays the number of pending credentialing applications over time. Pending applications are determined by taking the number of submitted applications and subtracting the number of fully processed applications (accept, reject, etc.).</p>
</section>
</div>
</div>
</div>

{% endblock %}
1 change: 1 addition & 0 deletions physionet-django/console/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,5 @@
path('usage/editorial/stats/', views.editorial_stats, name='editorial_stats'),
path('usage/credentialing/stats/', views.credentialing_stats,
name='credentialing_stats'),
path('usage/graph/stats/', views.graph_stats, name='graph_stats'),
]
35 changes: 35 additions & 0 deletions physionet-django/console/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1845,6 +1845,41 @@ def credentialing_stats(request):
'stats': stats})


@login_required
@user_passes_test(is_admin, redirect_field_name='project_home')
def graph_stats(request):
"""
Graphs.
"""
apps = CredentialApplication.objects.all()

now = datetime.now()
# Get the times of each application submission
app_times = [a.application_datetime for a in apps]
app_times.sort()
# Get the times of each application decision
des_times = [a.decision_datetime for a in apps if a.decision_datetime]
des_times.sort()
# Keep track of running total of applications in queue
all_times = app_times + des_times
all_times.sort()
net_apps = [0] * (len(all_times))
for i,t in enumerate(all_times):
if i > 0:
net_apps[i] = net_apps[i-1]
if t in app_times:
net_apps[i] += 1
if t in des_times:
net_apps[i] -= 1
# Convert datetime objects to readable form
timeline = [t.strftime("%d-%b-%y") for t in all_times]
timeline = ','.join(timeline)

return render(request, 'console/graph_stats.html',
{'stats_nav': True, 'submenu': 'graph',
'timeline': timeline, 'net_apps': net_apps})


@login_required
@user_passes_test(is_admin, redirect_field_name='project_home')
def download_credentialed_users(request):
Expand Down
2 changes: 1 addition & 1 deletion physionet-django/user/fixtures/demo-user.json
Original file line number Diff line number Diff line change
Expand Up @@ -9779,7 +9779,7 @@
"pk": 1,
"fields": {
"slug": "YgqTQmcerj0gLx4MAaZV",
"application_datetime": "2020-03-31T18:20:33.850Z",
"application_datetime": "2018-10-14T18:20:33.850Z",
"user": [
"rgmark"
],
Expand Down