Add dashboard to admin page
This commit is contained in:
parent
3d6ae08e84
commit
484e70a68f
17 changed files with 454 additions and 168 deletions
75
app/assets/javascripts/app/pages/admin_dashboard.js
Normal file
75
app/assets/javascripts/app/pages/admin_dashboard.js
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||||
|
|
||||||
|
app.pages.AdminDashboard = Backbone.View.extend({
|
||||||
|
initialize: function() {
|
||||||
|
this.updatePodStatus();
|
||||||
|
},
|
||||||
|
|
||||||
|
updatePodStatus: function() {
|
||||||
|
var self = this,
|
||||||
|
tagName = "";
|
||||||
|
$.get("https://api.github.com/repos/diaspora/diaspora/releases/latest")
|
||||||
|
.done(function(data) {
|
||||||
|
// the response might be malformed
|
||||||
|
try {
|
||||||
|
/* jshint camelcase: false */
|
||||||
|
tagName = data.tag_name;
|
||||||
|
/* jshint camelcase: true */
|
||||||
|
if(tagName.charAt(0) !== "v") {
|
||||||
|
self.updatePodStatusFail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
self.updatePodStatusFail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// split version into components
|
||||||
|
self.latestVersion = tagName.slice(1).split(".").map(Number);
|
||||||
|
if(self.podUpToDate() === null) {
|
||||||
|
self.updatePodStatusFail();
|
||||||
|
} else {
|
||||||
|
self.updatePodStatusSuccess();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.fail(function() {
|
||||||
|
self.updatePodStatusFail();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
updatePodStatusSuccess: function() {
|
||||||
|
$("#pod-status .alert").removeClass("alert-info");
|
||||||
|
var podStatusMessage = Diaspora.I18n.t("admins.dashboard.up_to_date");
|
||||||
|
if(this.podUpToDate()) {
|
||||||
|
$("#pod-status .alert").addClass("alert-success");
|
||||||
|
} else {
|
||||||
|
podStatusMessage = Diaspora.I18n.t("admins.dashboard.outdated");
|
||||||
|
$("#pod-status .alert").addClass("alert-danger");
|
||||||
|
}
|
||||||
|
$("#pod-status .alert")
|
||||||
|
.html("<strong>" + podStatusMessage + "</strong>")
|
||||||
|
.append(" ")
|
||||||
|
.append(Diaspora.I18n.t("admins.dashboard.compare_versions", {
|
||||||
|
latestVersion: "v" + this.latestVersion.join("."),
|
||||||
|
podVersion: "v" + gon.podVersion
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
updatePodStatusFail: function() {
|
||||||
|
$("#pod-status .alert")
|
||||||
|
.removeClass("alert-info")
|
||||||
|
.addClass("alert-warning")
|
||||||
|
.text(Diaspora.I18n.t("admins.dashboard.error"));
|
||||||
|
},
|
||||||
|
|
||||||
|
podUpToDate: function() {
|
||||||
|
var podVersion = gon.podVersion.split(/\.|\-/).map(Number);
|
||||||
|
if(this.latestVersion.length < 4 || podVersion.length < 4) { return null; }
|
||||||
|
for(var i = 0; i < 4; i++) {
|
||||||
|
if(this.latestVersion[i] < podVersion[i]) { return true; }
|
||||||
|
if(this.latestVersion[i] > podVersion[i]) { return false; }
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// @license-end
|
||||||
|
|
@ -10,6 +10,7 @@ app.Router = Backbone.Router.extend({
|
||||||
"user/edit": "settings",
|
"user/edit": "settings",
|
||||||
"users/sign_up": "registration",
|
"users/sign_up": "registration",
|
||||||
"profile/edit": "settings",
|
"profile/edit": "settings",
|
||||||
|
"admins/dashboard": "adminDashboard",
|
||||||
|
|
||||||
//new hotness
|
//new hotness
|
||||||
"posts/:id": "singlePost",
|
"posts/:id": "singlePost",
|
||||||
|
|
@ -47,6 +48,10 @@ app.Router = Backbone.Router.extend({
|
||||||
app.help.render(section);
|
app.help.render(section);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
adminDashboard: function() {
|
||||||
|
app.page = new app.pages.AdminDashboard();
|
||||||
|
},
|
||||||
|
|
||||||
contacts: function() {
|
contacts: function() {
|
||||||
app.aspect = new app.models.Aspect(gon.preloads.aspect);
|
app.aspect = new app.models.Aspect(gon.preloads.aspect);
|
||||||
app.contacts = new app.collections.Contacts(app.parsePreload("contacts"));
|
app.contacts = new app.collections.Contacts(app.parsePreload("contacts"));
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,6 @@
|
||||||
@import 'colors';
|
@import 'colors';
|
||||||
|
|
||||||
/** ADMIN STYlES **/
|
/** ADMIN STYlES **/
|
||||||
|
|
||||||
body > div.container {
|
|
||||||
margin-top: 40px;
|
|
||||||
padding-top: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
#admin_nav {
|
|
||||||
font-size: 1em;
|
|
||||||
border-bottom: 2px solid #777;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
|
|
||||||
ul {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
font-size: 0.8em;
|
|
||||||
display: inline;
|
|
||||||
margin-right: 0.5em;
|
|
||||||
|
|
||||||
a { color: $blue; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** user search **/
|
/** user search **/
|
||||||
|
|
||||||
.users {
|
.users {
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@
|
||||||
<li><a href="/user/edit">{{t "header.settings"}}</a></li>
|
<li><a href="/user/edit">{{t "header.settings"}}</a></li>
|
||||||
<li><a href="/help">{{t "header.help"}}</a></li>
|
<li><a href="/help">{{t "header.help"}}</a></li>
|
||||||
{{#if current_user.admin}}
|
{{#if current_user.admin}}
|
||||||
<li><a href="/admins/user_search">{{t "header.admin"}}</a></li>
|
<li><a href="/admins/dashboard">{{t "header.admin"}}</a></li>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<li><a href="/users/sign_out" data-method="delete">{{t "header.log_out"}}</a></li>
|
<li><a href="/users/sign_out" data-method="delete">{{t "header.log_out"}}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
class AdminsController < Admin::AdminController
|
class AdminsController < Admin::AdminController
|
||||||
|
include ApplicationHelper
|
||||||
|
|
||||||
|
def dashboard
|
||||||
|
gon.push(pod_version: pod_version)
|
||||||
|
end
|
||||||
|
|
||||||
def user_search
|
def user_search
|
||||||
if params[:admins_controller_user_search]
|
if params[:admins_controller_user_search]
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,21 @@
|
||||||
|
|
||||||
- content_for :head do
|
- content_for :head do
|
||||||
= stylesheet_link_tag :admin
|
= stylesheet_link_tag :admin
|
||||||
|
|
||||||
#admin_nav
|
%h2= t(".pages")
|
||||||
%h2
|
|
||||||
= t('.pages')
|
%ul#admin_nav.nav.nav-pills.nav-stacked
|
||||||
%ul
|
%li{role: "presentation", class: current_page?(admin_dashboard_path) && "active"}
|
||||||
%li= link_to t('.user_search'), user_search_path
|
= link_to t('.dashboard'), admin_dashboard_path
|
||||||
%li= link_to t('.weekly_user_stats'), weekly_user_stats_path
|
%li{role: "presentation", class: current_page?(user_search_path) && "active"}
|
||||||
%li= link_to t('.pod_stats'), pod_stats_path
|
= link_to t('.user_search'), user_search_path
|
||||||
%li= link_to t('.report'), report_index_path
|
%li{role: "presentation", class: current_page?(weekly_user_stats_path) && "active"}
|
||||||
%li= link_to t('.correlations'), correlations_path
|
= link_to t('.weekly_user_stats'), weekly_user_stats_path
|
||||||
%li= link_to t('.sidekiq_monitor'), sidekiq_path
|
%li{role: "presentation", class: current_page?(pod_stats_path) && "active"}
|
||||||
|
= link_to t('.pod_stats'), pod_stats_path
|
||||||
|
%li{role: "presentation", class: current_page?(report_index_path) && "active"}
|
||||||
|
= link_to t('.report'), report_index_path
|
||||||
|
%li{role: "presentation", class: current_page?(correlations_path) && "active"}
|
||||||
|
= link_to t('.correlations'), correlations_path
|
||||||
|
%li{role: "presentation", class: current_page?(sidekiq_path) && "active"}
|
||||||
|
= link_to t('.sidekiq_monitor'), sidekiq_path
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,8 @@
|
||||||
.container
|
.container
|
||||||
%div
|
.row
|
||||||
= render :partial => 'admins/admin_bar'
|
.col-md-3
|
||||||
|
= render partial: "admins/admin_bar"
|
||||||
%div.row
|
.col-md-9
|
||||||
%div.col-md-12
|
|
||||||
%h1
|
%h1
|
||||||
= t('.correlations_count')
|
= t('.correlations_count')
|
||||||
%ul
|
%ul
|
||||||
|
|
|
||||||
10
app/views/admins/dashboard.html.haml
Normal file
10
app/views/admins/dashboard.html.haml
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
.container
|
||||||
|
.row
|
||||||
|
.col-md-3
|
||||||
|
= render partial: "admins/admin_bar"
|
||||||
|
.col-md-9
|
||||||
|
#pod-status
|
||||||
|
%h2
|
||||||
|
= t(".pod_status")
|
||||||
|
.alert.alert-info{role: "alert"}
|
||||||
|
= t(".fetching_diaspora_version")
|
||||||
|
|
@ -1,56 +1,56 @@
|
||||||
.container
|
.container
|
||||||
%div
|
.row
|
||||||
= render :partial => 'admins/admin_bar'
|
.col-md-3
|
||||||
|
= render partial: "admins/admin_bar"
|
||||||
|
.col-md-9
|
||||||
|
%h1= t('.usage_statistic')
|
||||||
|
|
||||||
%h1
|
.pull-right
|
||||||
= t('.usage_statistic')
|
= form_tag('/admins/stats', :method => 'get', class: 'form-inline') do
|
||||||
|
%select{:name => 'range'}
|
||||||
|
%option{:value => 'daily', :selected => ('selected' if params[:range] == 'daily')}
|
||||||
|
= t('.daily')
|
||||||
|
%option{:value => 'week', :selected => ('selected' if params[:range] == 'week')}
|
||||||
|
= t('.week')
|
||||||
|
%option{:value => '2weeks', :selected => ('selected' if params[:range] == '2weeks')}
|
||||||
|
= t('.2weeks')
|
||||||
|
%option{:value => 'month', :selected => ('selected' if params[:range] == 'month')}
|
||||||
|
= t('.month')
|
||||||
|
|
||||||
%div.pull-right
|
= submit_tag t('.go'), class: 'btn btn-primary'
|
||||||
= form_tag('/admins/stats', :method => 'get', class: 'form-inline') do
|
|
||||||
%select{:name => 'range'}
|
|
||||||
%option{:value => 'daily', :selected => ('selected' if params[:range] == 'daily')}
|
|
||||||
= t('.daily')
|
|
||||||
%option{:value => 'week', :selected => ('selected' if params[:range] == 'week')}
|
|
||||||
= t('.week')
|
|
||||||
%option{:value => '2weeks', :selected => ('selected' if params[:range] == '2weeks')}
|
|
||||||
= t('.2weeks')
|
|
||||||
%option{:value => 'month', :selected => ('selected' if params[:range] == 'month')}
|
|
||||||
= t('.month')
|
|
||||||
|
|
||||||
= submit_tag t('.go'), class: 'btn btn-primary'
|
%h3
|
||||||
|
!= t('.display_results', :segment => @segment)
|
||||||
|
|
||||||
%h3
|
.row
|
||||||
!= t('.display_results', :segment => @segment)
|
- [:posts, :comments, :aspect_memberships, :users].each do |name|
|
||||||
|
- model = eval("@#{name.to_s}")
|
||||||
|
- if name == :aspect_memberships
|
||||||
|
- name = t('.shares', :count => model[:yesterday])
|
||||||
|
- if name == :posts
|
||||||
|
- name = t('.posts', :count => model[:yesterday])
|
||||||
|
- if name == :comments
|
||||||
|
- name = t('.comments', :count => model[:yesterday])
|
||||||
|
- if name == :users
|
||||||
|
- name = t('.users', :count => model[:yesterday])
|
||||||
|
|
||||||
%div.row
|
.col-md-3
|
||||||
- [:posts, :comments, :aspect_memberships, :users].each do |name|
|
%h2{:style => 'font-weight:bold;'}
|
||||||
- model = eval("@#{name.to_s}")
|
= name.to_s
|
||||||
- if name == :aspect_memberships
|
%h4
|
||||||
- name = t('.shares', :count => model[:yesterday])
|
= model[:day_before]
|
||||||
- if name == :posts
|
%span.percent_change{:class => (model[:change] > 0 ? "green" : "red")}
|
||||||
- name = t('.posts', :count => model[:yesterday])
|
= "(#{model[:change]}%)"
|
||||||
- if name == :comments
|
|
||||||
- name = t('.comments', :count => model[:yesterday])
|
|
||||||
- if name == :users
|
|
||||||
- name = t('.users', :count => model[:yesterday])
|
|
||||||
|
|
||||||
.col-md-3
|
.row
|
||||||
%h2{:style => 'font-weight:bold;'}
|
.col-md-12
|
||||||
= name.to_s
|
%p.alert.alert-info.text-center
|
||||||
%h4
|
!= t('.current_segment', :post_yest => @posts[:yesterday]/@user_count.to_f, :post_day => @posts[:day_before]/@user_count.to_f)
|
||||||
= model[:day_before]
|
|
||||||
%span.percent_change{:class => (model[:change] > 0 ? "green" : "red")}
|
|
||||||
= "(#{model[:change]}%)"
|
|
||||||
|
|
||||||
%div.row
|
.row
|
||||||
%div.col-md-12
|
.col-md-12
|
||||||
%p.alert.alert-info.text-center
|
%h3= t('.50_most')
|
||||||
!= t('.current_segment', :post_yest => @posts[:yesterday]/@user_count.to_f, :post_day => @posts[:day_before]/@user_count.to_f)
|
%ul
|
||||||
|
- @popular_tags.each do |name,count|
|
||||||
%div.row
|
%li
|
||||||
%div.col-md-12
|
!= t('.tag_name', :name_tag => name, :count_tag => count)
|
||||||
%h3= t('.50_most')
|
|
||||||
%ul
|
|
||||||
- @popular_tags.each do |name,count|
|
|
||||||
%li
|
|
||||||
!= t('.tag_name', :name_tag => name, :count_tag => count)
|
|
||||||
|
|
|
||||||
|
|
@ -1,58 +1,59 @@
|
||||||
.container
|
.container
|
||||||
%div
|
.row
|
||||||
= render :partial => 'admins/admin_bar'
|
.col-md-3
|
||||||
|
= render partial: "admins/admin_bar"
|
||||||
|
.col-md-9
|
||||||
|
.row
|
||||||
|
.user_search.col-md-8
|
||||||
|
%h3= t('admins.admin_bar.user_search')
|
||||||
|
= form_for @search, url: {action: 'user_search'}, html: {method: :get, class: 'form-horizontal'} do |f|
|
||||||
|
.form-group
|
||||||
|
= f.label :username, t('username'), class: 'col-sm-2 control-label'
|
||||||
|
.col-sm-10
|
||||||
|
= f.text_field :username, class: "form-control"
|
||||||
|
|
||||||
%div.row
|
.form-group
|
||||||
%div.user_search.col-md-8
|
= f.label :email, t('email'), class: 'col-sm-2 control-label'
|
||||||
%h3= t('admins.admin_bar.user_search')
|
.col-sm-10
|
||||||
= form_for @search, url: {action: 'user_search'}, html: {method: :get, class: 'form-horizontal'} do |f|
|
= f.text_field :email, class: "form-control"
|
||||||
%div.form-group
|
|
||||||
= f.label :username, t('username'), class: 'col-sm-2 control-label'
|
|
||||||
%div.col-sm-10
|
|
||||||
= f.text_field :username, class: "form-control"
|
|
||||||
|
|
||||||
%div.form-group
|
.form-group
|
||||||
= f.label :email, t('email'), class: 'col-sm-2 control-label'
|
= f.label :guid, t('admins.user_entry.guid'), class: 'col-sm-2 control-label'
|
||||||
%div.col-sm-10
|
.col-sm-10
|
||||||
= f.text_field :email, class: "form-control"
|
= f.text_field :guid, class: "form-control"
|
||||||
|
|
||||||
%div.form-group
|
.form-group
|
||||||
= f.label :guid, t('admins.user_entry.guid'), class: 'col-sm-2 control-label'
|
.col-sm-offset-2.col-sm-10
|
||||||
%div.col-sm-10
|
= f.label :under13 do
|
||||||
= f.text_field :guid, class: "form-control"
|
= f.check_box :under13
|
||||||
|
= t(".under_13")
|
||||||
|
.form-group
|
||||||
|
.clearfix.col-sm-12
|
||||||
|
= submit_tag t("admins.stats.go"), class: "btn btn-primary pull-right"
|
||||||
|
|
||||||
%div.form-group
|
.more_invites.col-md-4
|
||||||
%div.col-sm-offset-2.col-sm-10
|
%h3= t("shared.invitations.invites")
|
||||||
= f.label :under13 do
|
#add-invites-section.clearfix
|
||||||
= f.check_box :under13
|
!= t(".you_currently", count: current_user.invitation_code.count,
|
||||||
= t(".under_13")
|
link: link_to(t(".add_invites"), add_invites_path(current_user.invitation_code),
|
||||||
%div.form-group
|
class: "btn btn-link pull-right"))
|
||||||
%div.clearfix.col-sm-12
|
|
||||||
= submit_tag t("admins.stats.go"), class: "btn btn-primary pull-right"
|
|
||||||
|
|
||||||
%div.more_invites.col-md-4
|
= form_tag "admin_inviter", method: :get, class: "form-horizontal" do
|
||||||
%h3= t("shared.invitations.invites")
|
.form-group
|
||||||
#add-invites-section.clearfix
|
%label.col-sm-4.control-label
|
||||||
!= t(".you_currently", count: current_user.invitation_code.count,
|
= t(".email_to")
|
||||||
link: link_to(t(".add_invites"), add_invites_path(current_user.invitation_code),
|
.col-sm-8
|
||||||
class: "btn btn-link pull-right"))
|
= text_field_tag "identifier", nil, class: "form-control"
|
||||||
|
.form-group
|
||||||
|
.clearfix.col-md-12
|
||||||
|
= submit_tag t("services.remote_friend.invite"), class: "btn btn-default pull-right"
|
||||||
|
|
||||||
= form_tag "admin_inviter", method: :get, class: "form-horizontal" do
|
.row
|
||||||
.form-group
|
.col-md-12
|
||||||
%label.col-sm-4.control-label
|
.alert.alert-info.text-center= t('.users', :count => @users.count)
|
||||||
= t(".email_to")
|
|
||||||
.col-sm-8
|
|
||||||
= text_field_tag "identifier", nil, class: "form-control"
|
|
||||||
.form-group
|
|
||||||
.clearfix.col-md-12
|
|
||||||
= submit_tag t("services.remote_friend.invite"), class: "btn btn-default pull-right"
|
|
||||||
|
|
||||||
%div.row
|
.row
|
||||||
%div.col-md-12
|
.users.col-md-12
|
||||||
%div.alert.alert-info.text-center= t('.users', :count => @users.count)
|
%ul.media-list
|
||||||
|
- @users.each do |user|
|
||||||
%div.row
|
= render partial: 'user_entry', locals: { user: user }
|
||||||
%div.users.col-md-12
|
|
||||||
%ul.media-list
|
|
||||||
- @users.each do |user|
|
|
||||||
= render partial: 'user_entry', locals: { user: user }
|
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,18 @@
|
||||||
.container
|
.container
|
||||||
%div
|
.row
|
||||||
= render :partial => 'admins/admin_bar'
|
.col-md-3
|
||||||
|
= render partial: "admins/admin_bar"
|
||||||
|
.col-md-9
|
||||||
|
%h2
|
||||||
|
= t('.current_server', date: Time.now.to_date)
|
||||||
|
|
||||||
%h2
|
.pull-right
|
||||||
= t('.current_server', date: Time.now.to_date)
|
= form_tag('/admins/weekly_user_stats', method: 'get', class: 'form-inline') do
|
||||||
|
= select_tag(:week, options_for_select(@created_users_by_week.keys.reverse, @selected_week))
|
||||||
|
= submit_tag t('admins.stats.go'), class: 'btn btn-primary'
|
||||||
|
|
||||||
%div.pull-right
|
= t('.amount_of', count: @counter)
|
||||||
= form_tag('/admins/weekly_user_stats', method: 'get', class: 'form-inline') do
|
%br
|
||||||
= select_tag(:week, options_for_select(@created_users_by_week.keys.reverse, @selected_week))
|
- @created_users_by_week[@selected_week].each do |m|
|
||||||
= submit_tag t('admins.stats.go'), class: 'btn btn-primary'
|
= link_to m, "/u/#{m}"
|
||||||
|
%br
|
||||||
= t('.amount_of', count: @counter)
|
|
||||||
%br
|
|
||||||
- @created_users_by_week[@selected_week].each do |m|
|
|
||||||
= link_to m, "/u/#{m}"
|
|
||||||
%br
|
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,21 @@
|
||||||
.container
|
.container
|
||||||
%div
|
.row
|
||||||
= render :partial => 'admins/admin_bar'
|
.col-md-3
|
||||||
|
= render partial: "admins/admin_bar"
|
||||||
%div.row
|
.col-md-9
|
||||||
%div.col-md-12
|
|
||||||
%h1
|
%h1
|
||||||
= t('report.title')
|
= t('report.title')
|
||||||
%div#reports
|
#reports
|
||||||
- @reports.each do |r|
|
- @reports.each do |r|
|
||||||
- username = User.find_by_id(r.user_id).username
|
- username = User.find_by_id(r.user_id).username
|
||||||
%div.content
|
.content
|
||||||
%span.text
|
%span.text
|
||||||
= report_content(r.item_id, r.item_type)
|
= report_content(r.item_id, r.item_type)
|
||||||
%span
|
%span
|
||||||
= raw t('report.reported_label', person: link_to(username, user_profile_path(username)))
|
= raw t('report.reported_label', person: link_to(username, user_profile_path(username)))
|
||||||
%span
|
%span
|
||||||
= t('report.reason_label', text: r.text)
|
= t('report.reason_label', text: r.text)
|
||||||
%div.options.text-right
|
.options.text-right
|
||||||
%span
|
%span
|
||||||
= button_to t('report.review_link'), report_path(r.id, :type => r.item_type),
|
= button_to t('report.review_link'), report_path(r.id, :type => r.item_type),
|
||||||
:class => "btn btn-info btn-small",
|
:class => "btn btn-info btn-small",
|
||||||
|
|
@ -26,4 +25,4 @@
|
||||||
:data => { :confirm => t('report.confirm_deletion') },
|
:data => { :confirm => t('report.confirm_deletion') },
|
||||||
:class => "btn btn-danger btn-small",
|
:class => "btn btn-danger btn-small",
|
||||||
method: :delete
|
method: :delete
|
||||||
%div.clear
|
.clear
|
||||||
|
|
|
||||||
|
|
@ -98,12 +98,16 @@ en:
|
||||||
admins:
|
admins:
|
||||||
admin_bar:
|
admin_bar:
|
||||||
pages: "Pages"
|
pages: "Pages"
|
||||||
|
dashboard: "Dashboard"
|
||||||
user_search: "User search"
|
user_search: "User search"
|
||||||
weekly_user_stats: "Weekly user stats"
|
weekly_user_stats: "Weekly user stats"
|
||||||
pod_stats: "Pod stats"
|
pod_stats: "Pod stats"
|
||||||
report: "Reports"
|
report: "Reports"
|
||||||
correlations: "Correlations"
|
correlations: "Correlations"
|
||||||
sidekiq_monitor: "Sidekiq monitor"
|
sidekiq_monitor: "Sidekiq monitor"
|
||||||
|
dashboard:
|
||||||
|
pod_status: "Pod status"
|
||||||
|
fetching_diaspora_version: "Fetching current diaspora* version..."
|
||||||
correlations:
|
correlations:
|
||||||
correlations_count: "Correlations with sign-in count:"
|
correlations_count: "Correlations with sign-in count:"
|
||||||
user_search:
|
user_search:
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,13 @@ en:
|
||||||
edit: "Edit"
|
edit: "Edit"
|
||||||
no_results: "No results found"
|
no_results: "No results found"
|
||||||
|
|
||||||
|
admins:
|
||||||
|
dashboard:
|
||||||
|
up_to_date: "Your pod is up to date!"
|
||||||
|
outdated: "Your pod is outdated."
|
||||||
|
compare_versions: "The latest diaspora* release is <%= latestVersion %>, your pod is running <%= podVersion %>."
|
||||||
|
error: "Error fetching the latest diaspora* version."
|
||||||
|
|
||||||
aspects:
|
aspects:
|
||||||
make_aspect_list_visible: "Make contacts in this aspect visible to each other?"
|
make_aspect_list_visible: "Make contacts in this aspect visible to each other?"
|
||||||
name: "Name"
|
name: "Name"
|
||||||
|
|
|
||||||
|
|
@ -141,13 +141,14 @@ Diaspora::Application.routes.draw do
|
||||||
|
|
||||||
# Admin backend routes
|
# Admin backend routes
|
||||||
|
|
||||||
scope 'admins', :controller => :admins do
|
scope "admins", controller: :admins do
|
||||||
match :user_search, via: [:get, :post]
|
match :user_search, via: [:get, :post]
|
||||||
get :admin_inviter
|
get :admin_inviter
|
||||||
get :weekly_user_stats
|
get :weekly_user_stats
|
||||||
get :correlations
|
get :correlations
|
||||||
get :stats, :as => 'pod_stats'
|
get :stats, as: "pod_stats"
|
||||||
get "add_invites/:invite_code_id" => 'admins#add_invites', :as => 'add_invites'
|
get :dashboard, as: "admin_dashboard"
|
||||||
|
get "add_invites/:invite_code_id" => "admins#add_invites", :as => "add_invites"
|
||||||
end
|
end
|
||||||
|
|
||||||
namespace :admin do
|
namespace :admin do
|
||||||
|
|
|
||||||
18
spec/controllers/jasmine_fixtures/admins_spec.rb
Normal file
18
spec/controllers/jasmine_fixtures/admins_spec.rb
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
require "spec_helper"
|
||||||
|
|
||||||
|
describe AdminsController, type: :controller do
|
||||||
|
describe "#dashboard" do
|
||||||
|
before do
|
||||||
|
@user = FactoryGirl.create :user
|
||||||
|
Role.add_admin(@user.person)
|
||||||
|
sign_in :user, @user
|
||||||
|
end
|
||||||
|
|
||||||
|
context "jasmine fixtures" do
|
||||||
|
it "generates a jasmine fixture", fixture: true do
|
||||||
|
get :dashboard
|
||||||
|
save_fixture(html_for("body"), "admin_dashboard")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
179
spec/javascripts/app/pages/admin_dashboard_spec.js
Normal file
179
spec/javascripts/app/pages/admin_dashboard_spec.js
Normal file
|
|
@ -0,0 +1,179 @@
|
||||||
|
describe("app.pages.AdminDashboard", function(){
|
||||||
|
beforeEach(function() {
|
||||||
|
spec.loadFixture("admin_dashboard");
|
||||||
|
this.view = new app.pages.AdminDashboard();
|
||||||
|
gon.podVersion = "0.5.1.2";
|
||||||
|
// disable jshint camelcase for i18n
|
||||||
|
/* jshint camelcase: false */
|
||||||
|
Diaspora.I18n.load({
|
||||||
|
admins: {
|
||||||
|
dashboard: {
|
||||||
|
up_to_date: "Your pod is up to date!",
|
||||||
|
outdated: "Your pod is outdated.",
|
||||||
|
compare_versions: "Latest d* release is <%= latestVersion%>, your pod is running <%= podVersion %>.",
|
||||||
|
error: "Error fetching the latest diaspora* version."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
/* jshint camelcase: true */
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("initialize" , function() {
|
||||||
|
it("calls updatePodStatus", function() {
|
||||||
|
spyOn(this.view, "updatePodStatus");
|
||||||
|
this.view.initialize();
|
||||||
|
expect(this.view.updatePodStatus).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("updatePodStatus" , function() {
|
||||||
|
it("sends an ajax request to the github API", function() {
|
||||||
|
this.view.updatePodStatus();
|
||||||
|
expect(jasmine.Ajax.requests.mostRecent().url).toBe(
|
||||||
|
"https://api.github.com/repos/diaspora/diaspora/releases/latest"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("calls updatePodStatusFail on a failed request", function() {
|
||||||
|
spyOn(this.view, "updatePodStatusFail");
|
||||||
|
this.view.updatePodStatus();
|
||||||
|
jasmine.Ajax.requests.mostRecent().respondWith({status: 400});
|
||||||
|
expect(this.view.updatePodStatusFail).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("calls updatePodStatusFail on a malformed response", function() {
|
||||||
|
spyOn(this.view, "updatePodStatusFail");
|
||||||
|
spyOn(this.view, "podUpToDate").and.returnValue(true);
|
||||||
|
var responses = [
|
||||||
|
// no object
|
||||||
|
"text",
|
||||||
|
// object without tag_name
|
||||||
|
"{\"tag\": 0}",
|
||||||
|
// tag_name not a string
|
||||||
|
"{\"tag_name\": 0}",
|
||||||
|
"{\"tag_name\": {\"id\": 0}}",
|
||||||
|
// tag_name doesn't start with "v"
|
||||||
|
"{\"tag_name\": \"0.5.1.2\"}"
|
||||||
|
];
|
||||||
|
|
||||||
|
for(var i = 0; i < responses.length; i++) {
|
||||||
|
this.view.updatePodStatus();
|
||||||
|
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||||
|
status: 200,
|
||||||
|
responseText: responses[i]
|
||||||
|
});
|
||||||
|
expect(this.view.updatePodStatusFail.calls.count()).toEqual(i+1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("sets latestVersion on a correct response", function() {
|
||||||
|
this.view.updatePodStatus();
|
||||||
|
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||||
|
status: 200,
|
||||||
|
responseText: "{\"tag_name\": \"v0.5.1.2\"}"
|
||||||
|
});
|
||||||
|
expect(this.view.latestVersion).toEqual([0,5,1,2]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("calls podUpToDate on a correct response", function() {
|
||||||
|
spyOn(this.view, "podUpToDate");
|
||||||
|
this.view.updatePodStatus();
|
||||||
|
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||||
|
status: 200,
|
||||||
|
responseText: "{\"tag_name\": \"v0.5.1.2\"}"
|
||||||
|
});
|
||||||
|
expect(this.view.podUpToDate).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("calls updatePodStatusFail if podUpToDate returns null", function() {
|
||||||
|
spyOn(this.view, "updatePodStatusFail");
|
||||||
|
spyOn(this.view, "podUpToDate").and.returnValue(null);
|
||||||
|
this.view.updatePodStatus();
|
||||||
|
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||||
|
status: 200,
|
||||||
|
responseText: "{\"tag_name\": \"v0.5.1.2\"}"
|
||||||
|
});
|
||||||
|
expect(this.view.updatePodStatusFail).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("calls updatePodStatusSuccess if podUpToDate returns a Boolean", function() {
|
||||||
|
spyOn(this.view, "updatePodStatusSuccess");
|
||||||
|
spyOn(this.view, "podUpToDate").and.returnValue(false);
|
||||||
|
this.view.updatePodStatus();
|
||||||
|
jasmine.Ajax.requests.mostRecent().respondWith({
|
||||||
|
status: 200,
|
||||||
|
responseText: "{\"tag_name\": \"v0.5.1.2\"}"
|
||||||
|
});
|
||||||
|
expect(this.view.updatePodStatusSuccess).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("podUpToDate" , function() {
|
||||||
|
it("returns null if latestVersion is not long enough", function() {
|
||||||
|
this.view.latestVersion = [0, 5, 1];
|
||||||
|
expect(this.view.podUpToDate()).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns true if the pod is up to date", function() {
|
||||||
|
var self = this;
|
||||||
|
[
|
||||||
|
{latest: "0.5.1.2", pod: "0.5.1.2"},
|
||||||
|
{latest: "0.5.1.2", pod: "0.5.1.2-abcdefg"},
|
||||||
|
{latest: "0.5.1.2", pod: "0.5.1.2-2"},
|
||||||
|
{latest: "0.5.1.2", pod: "0.5.1.3"},
|
||||||
|
{latest: "0.5.1.2", pod: "0.5.2.1"},
|
||||||
|
{latest: "0.5.1.2", pod: "0.6.0.0"},
|
||||||
|
{latest: "0.5.1.2", pod: "2.0.0.0"}
|
||||||
|
].forEach(function(version) {
|
||||||
|
gon.podVersion = version.pod;
|
||||||
|
self.view.latestVersion = version.latest.split(".").map(Number);
|
||||||
|
expect(self.view.podUpToDate()).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns false if the pod is outdated", function() {
|
||||||
|
var self = this;
|
||||||
|
[
|
||||||
|
{latest: "0.5.1.2", pod: "0.5.1.1"},
|
||||||
|
{latest: "0.5.1.2", pod: "0.5.1.1-abcdefg"},
|
||||||
|
{latest: "0.5.1.2", pod: "0.5.1.1-2"},
|
||||||
|
{latest: "0.5.1.2", pod: "0.4.99.4"},
|
||||||
|
{latest: "2.0.3.5", pod: "1.99.2.1"}
|
||||||
|
].forEach(function(version) {
|
||||||
|
gon.podVersion = version.pod;
|
||||||
|
self.view.latestVersion = version.latest.split(".").map(Number);
|
||||||
|
expect(self.view.podUpToDate()).toBeFalsy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("updatePodStatusSuccess", function() {
|
||||||
|
it("adds a 'success' alert if the pod is up to date", function() {
|
||||||
|
spyOn(this.view, "podUpToDate").and.returnValue(true);
|
||||||
|
this.view.latestVersion = [0, 5, 1, 1];
|
||||||
|
this.view.updatePodStatusSuccess();
|
||||||
|
expect($("#pod-status .alert")).toHaveClass("alert-success");
|
||||||
|
expect($("#pod-status .alert").text()).toContain("up to date");
|
||||||
|
expect($("#pod-status .alert").text()).toContain("release is v0.5.1.1");
|
||||||
|
expect($("#pod-status .alert").text()).toContain("pod is running v0.5.1.2");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("adds a 'danger' alert if the pod is up to date", function() {
|
||||||
|
spyOn(this.view, "podUpToDate").and.returnValue(false);
|
||||||
|
this.view.latestVersion = [0, 5, 1, 3];
|
||||||
|
this.view.updatePodStatusSuccess();
|
||||||
|
expect($("#pod-status .alert")).toHaveClass("alert-danger");
|
||||||
|
expect($("#pod-status .alert").text()).toContain("outdated");
|
||||||
|
expect($("#pod-status .alert").text()).toContain("release is v0.5.1.3");
|
||||||
|
expect($("#pod-status .alert").text()).toContain("pod is running v0.5.1.2");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("updatePodStatusFail", function() {
|
||||||
|
it("adds a 'warning' alert", function() {
|
||||||
|
this.view.updatePodStatusFail();
|
||||||
|
expect($("#pod-status .alert")).toHaveClass("alert-warning");
|
||||||
|
expect($("#pod-status .alert").text()).toContain("Error");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue