add ActiveAdmin
1
Gemfile
@ -29,6 +29,7 @@ gem 'capistrano', '~> 2.15.4'
|
||||
gem 'rack-utf8_sanitizer'
|
||||
gem 'newrelic_rpm'
|
||||
gem 'actionpack-xml_parser'
|
||||
gem 'activeadmin', github: 'gregbell/active_admin'
|
||||
|
||||
# to use debugger
|
||||
# gem 'ruby-debug'
|
||||
|
45
Gemfile.lock
@ -1,3 +1,21 @@
|
||||
GIT
|
||||
remote: git://github.com/gregbell/active_admin.git
|
||||
revision: 3fb7f03335b1ec5743c305f2c37103e2bfface97
|
||||
specs:
|
||||
activeadmin (1.0.0.pre)
|
||||
arbre (~> 1.0)
|
||||
bourbon
|
||||
coffee-rails
|
||||
devise (~> 3.2)
|
||||
formtastic (~> 2.3.0.rc2)
|
||||
inherited_resources (~> 1.3)
|
||||
jquery-rails
|
||||
jquery-ui-rails
|
||||
kaminari (~> 0.15)
|
||||
rails (>= 3.2, < 4.1)
|
||||
ransack (~> 1.0)
|
||||
sass-rails
|
||||
|
||||
GIT
|
||||
remote: git://github.com/moomerman/twitter_oauth.git
|
||||
revision: 04e6bbfe635a376cae342d234214cdab864fe797
|
||||
@ -51,6 +69,8 @@ GEM
|
||||
annotate (2.6.1)
|
||||
activerecord (>= 2.3.0)
|
||||
rake (>= 0.8.7)
|
||||
arbre (1.0.1)
|
||||
activesupport (>= 3.0.0)
|
||||
arel (4.0.2)
|
||||
atomic (1.1.14)
|
||||
autotest (4.4.6)
|
||||
@ -60,6 +80,9 @@ GEM
|
||||
bcrypt (3.1.7)
|
||||
bcrypt-ruby (3.1.5)
|
||||
bcrypt (>= 3.1.3)
|
||||
bourbon (3.1.8)
|
||||
sass (>= 3.2.0)
|
||||
thor
|
||||
builder (3.1.4)
|
||||
capistrano (2.15.4)
|
||||
highline
|
||||
@ -117,9 +140,14 @@ GEM
|
||||
i18n (~> 0.5)
|
||||
faraday (0.8.9)
|
||||
multipart-post (~> 1.2.0)
|
||||
formtastic (2.3.0.rc2)
|
||||
actionpack (>= 3.0)
|
||||
geokit (1.8.4)
|
||||
multi_json (>= 1.3.2)
|
||||
gravatarify (3.1.0)
|
||||
has_scope (0.6.0.rc)
|
||||
actionpack (>= 3.2, < 5)
|
||||
activesupport (>= 3.2, < 5)
|
||||
highline (1.6.20)
|
||||
hike (1.2.3)
|
||||
http_parser.rb (0.6.0)
|
||||
@ -132,13 +160,21 @@ GEM
|
||||
rake
|
||||
term-ansicolor
|
||||
terminal-table
|
||||
inherited_resources (1.4.1)
|
||||
has_scope (~> 0.6.0.rc)
|
||||
responders (~> 1.0.0.rc)
|
||||
jquery-rails (3.0.4)
|
||||
railties (>= 3.0, < 5.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
jquery-ui-rails (4.2.0)
|
||||
railties (>= 3.2.16)
|
||||
json (1.8.1)
|
||||
json_spec (1.1.1)
|
||||
multi_json (~> 1.0)
|
||||
rspec (~> 2.0)
|
||||
kaminari (0.15.1)
|
||||
actionpack (>= 3.0.0)
|
||||
activesupport (>= 3.0.0)
|
||||
kgio (2.8.1)
|
||||
libv8 (3.16.14.3)
|
||||
mail (2.5.4)
|
||||
@ -164,6 +200,8 @@ GEM
|
||||
mini_portile (~> 0.5.0)
|
||||
oauth (0.4.7)
|
||||
orm_adapter (0.5.0)
|
||||
polyamorous (0.6.4)
|
||||
activerecord (>= 3.0)
|
||||
polyglot (0.3.4)
|
||||
quiet_assets (1.0.2)
|
||||
railties (>= 3.1, < 5.0)
|
||||
@ -190,10 +228,16 @@ GEM
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.18.1, < 2.0)
|
||||
rake (10.1.1)
|
||||
ransack (1.1.0)
|
||||
actionpack (>= 3.0)
|
||||
activerecord (>= 3.0)
|
||||
polyamorous (~> 0.6.0)
|
||||
redis (3.0.7)
|
||||
redis-namespace (1.4.1)
|
||||
redis (~> 3.0.4)
|
||||
ref (1.0.5)
|
||||
responders (1.0.0)
|
||||
railties (>= 3.2, < 5)
|
||||
resque (1.25.1)
|
||||
mono_logger (~> 1.0)
|
||||
multi_json (~> 1.0)
|
||||
@ -296,6 +340,7 @@ PLATFORMS
|
||||
DEPENDENCIES
|
||||
ZenTest
|
||||
actionpack-xml_parser
|
||||
activeadmin!
|
||||
acts_as_list
|
||||
acts_as_tree
|
||||
annotate (~> 2.6.1)
|
||||
|
25
app/admin/channel.rb
Normal file
@ -0,0 +1,25 @@
|
||||
ActiveAdmin.register Channel do
|
||||
|
||||
filter :name
|
||||
filter :description
|
||||
filter :created_at
|
||||
|
||||
permit_params :name, :public_flag
|
||||
|
||||
index do
|
||||
column :id
|
||||
column(:name) { |channel| link_to channel.name, channel }
|
||||
column(:user) { |channel| link_to channel.user.login, admin_user_path(channel.user) if channel.user.present? }
|
||||
column :public_flag
|
||||
column :created_at
|
||||
default_actions
|
||||
end
|
||||
|
||||
form do |f|
|
||||
f.semantic_errors *f.object.errors.keys
|
||||
f.inputs :name, :public_flag
|
||||
f.actions
|
||||
end
|
||||
|
||||
end
|
||||
|
28
app/admin/dashboard.rb
Normal file
@ -0,0 +1,28 @@
|
||||
ActiveAdmin.register_page "Dashboard" do
|
||||
|
||||
menu priority: 1, label: proc{ I18n.t("active_admin.dashboard") }
|
||||
|
||||
content title: proc{ I18n.t("active_admin.dashboard") } do
|
||||
columns do
|
||||
|
||||
column do
|
||||
panel "Stats" do
|
||||
para "Total Users: #{User.all.count}"
|
||||
para "Total Channels: #{Channel.all.count}"
|
||||
end
|
||||
end
|
||||
|
||||
column do
|
||||
panel "Recent Channels" do
|
||||
ul do
|
||||
Channel.all.order("created_at desc").limit(5).map do |channel|
|
||||
li link_to(channel.name, admin_channel_path(channel))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end # content
|
||||
end
|
||||
|
19
app/admin/failedlogin.rb
Normal file
@ -0,0 +1,19 @@
|
||||
ActiveAdmin.register Failedlogin do
|
||||
menu :parent => "Others"
|
||||
actions :all, :except => [:edit]
|
||||
|
||||
filter :login
|
||||
filter :password
|
||||
filter :created_at
|
||||
|
||||
index do
|
||||
column :id
|
||||
column :login
|
||||
column :password
|
||||
column :ip_address
|
||||
column :created_at
|
||||
default_actions
|
||||
end
|
||||
|
||||
end
|
||||
|
23
app/admin/plugin.rb
Normal file
@ -0,0 +1,23 @@
|
||||
ActiveAdmin.register Plugin do
|
||||
|
||||
filter :name
|
||||
filter :created_at
|
||||
|
||||
permit_params :name, :html, :css, :js, :private_flag
|
||||
|
||||
index do
|
||||
column :id
|
||||
column(:user) { |object| link_to object.user.login, admin_user_path(object.user) if object.user.present? }
|
||||
column :name
|
||||
column :private_flag
|
||||
default_actions
|
||||
end
|
||||
|
||||
form do |f|
|
||||
f.semantic_errors *f.object.errors.keys
|
||||
f.inputs :name, :html, :css, :js, :private_flag
|
||||
f.actions
|
||||
end
|
||||
|
||||
end
|
||||
|
9
app/admin/useful_links.rb
Normal file
@ -0,0 +1,9 @@
|
||||
ActiveAdmin.register_page "Useful Links" do
|
||||
menu :parent => "Others"
|
||||
|
||||
content do
|
||||
render "index"
|
||||
end
|
||||
|
||||
end
|
||||
|
48
app/admin/user.rb
Normal file
@ -0,0 +1,48 @@
|
||||
ActiveAdmin.register User do
|
||||
require 'csv'
|
||||
|
||||
filter :email
|
||||
filter :login
|
||||
filter :created_at
|
||||
|
||||
permit_params :email, :login, :bio, :website
|
||||
|
||||
index do
|
||||
column :id
|
||||
column :email
|
||||
column :login
|
||||
column :created_at
|
||||
default_actions
|
||||
end
|
||||
|
||||
show do
|
||||
attributes_table do
|
||||
rows :id, :email, :login, :time_zone, :bio, :website, :created_at, :sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip, :last_sign_in_ip
|
||||
end
|
||||
panel 'Channels' do
|
||||
table_for user.channels do
|
||||
column :id
|
||||
column(:name) { |channel| link_to channel.name, channel }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
form do |f|
|
||||
f.semantic_errors *f.object.errors.keys
|
||||
f.inputs :email, :login
|
||||
f.actions
|
||||
end
|
||||
|
||||
# custom action for signups per day
|
||||
collection_action :signups, :method => :get, :format => :csv do
|
||||
@csv_headers = [:day, :signups]
|
||||
@days = User.signups_per_day
|
||||
end
|
||||
|
||||
# custom action for emails list
|
||||
collection_action :emails, :method => :get do
|
||||
@users = User.all
|
||||
end
|
||||
|
||||
end
|
||||
|
BIN
app/assets/images/ajax-loader.gif
Normal file
After Width: | Height: | Size: 3.1 KiB |
2
app/assets/javascripts/active_admin.js.coffee
Normal file
@ -0,0 +1,2 @@
|
||||
#= require active_admin/base
|
||||
|
@ -208,7 +208,7 @@ o(b[3],a[3]);this.axisOffset=[0,0,0,0];this.clipOffset=[0,0,0,0]},drawChartBox:f
|
||||
null,null,c-p,d-p));else{e={fill:j||Q};if(i)e.stroke=a.borderColor,e["stroke-width"]=i;this.chartBackground=b.rect(p/2,p/2,c-p,d-p,a.borderRadius,i).attr(e).add().shadow(a.shadow)}if(k)f?f.animate(s):this.plotBackground=b.rect(q,o,n,t,0).attr({fill:k}).add().shadow(a.plotShadow);if(l)h?h.animate(s):this.plotBGImage=b.image(l,q,o,n,t).add();r?r.animate({width:w.width,height:w.height}):this.clipRect=b.clipRect(w);if(m)g?g.animate(g.crisp(null,q,o,n,t)):this.plotBorder=b.rect(q,o,n,t,0,-m).attr({stroke:a.plotBorderColor,
|
||||
"stroke-width":m,zIndex:1}).add();this.isDirtyBox=!1},propFromSeries:function(){var a=this,b=a.options.chart,c,d=a.options.series,e,f;n(["inverted","angular","polar"],function(g){c=L[b.type||b.defaultSeriesType];f=a[g]||b[g]||c&&c.prototype[g];for(e=d&&d.length;!f&&e--;)(c=L[d[e].type])&&c.prototype[g]&&(f=!0);a[g]=f})},linkSeries:function(){var a=this,b=a.series;n(b,function(a){a.linkedSeries.length=0});n(b,function(b){var d=b.options.linkedTo;if(da(d)&&(d=d===":previous"?a.series[b.index-1]:a.get(d)))d.linkedSeries.push(b),
|
||||
b.linkedParent=d})},render:function(){var a=this,b=a.axes,c=a.renderer,d=a.options,e=d.labels,f=d.credits,g;a.setTitle();a.legend=new zb(a,d.legend);a.getStacks();n(b,function(a){a.setScale()});a.getMargins();a.maxTicks=null;n(b,function(a){a.setTickPositions(!0);a.setMaxTicks()});a.adjustTickAmounts();a.getMargins();a.drawChartBox();a.hasCartesianSeries&&n(b,function(a){a.render()});if(!a.seriesGroup)a.seriesGroup=c.g("series-group").attr({zIndex:3}).add();n(a.series,function(a){a.translate();a.setTooltipPoints();
|
||||
a.render()});e.items&&n(e.items,function(b){var d=r(e.style,b.style),f=z(d.left)+a.plotLeft,g=z(d.top)+a.plotTop+12;delete d.left;delete d.top;c.text(b.html,f,g).attr({zIndex:2}).css(d).add()});if(f.enabled&&!a.credits)g=f.href,a.credits=c.text(f.text,0,0).on("click",function(){if(g)location.href=g}).attr({align:f.position.align,zIndex:8}).css(f.style).add().align(f.position);a.hasRendered=!0},destroy:function(){var a=this,b=a.axes,c=a.series,d=a.container,e,f=d&&d.parentNode;A(a,"destroy");Ja[a.index]=
|
||||
a.render()});e.items&&n(e.items,function(b){var d=r(e.style,b.style),f=z(d.left)+a.plotLeft,g=z(d.top)+a.plotTop+12;delete d.left;delete d.top;c.text(b.html,f,g).attr({zIndex:2}).css(d).add()});if(f.enabled&&!a.credits)g=f.href,a.credits=c.text(f.text,0,0).on("click",function(){if(g)parent.location.href=g}).attr({align:f.position.align,zIndex:8}).css(f.style).add().align(f.position);a.hasRendered=!0},destroy:function(){var a=this,b=a.axes,c=a.series,d=a.container,e,f=d&&d.parentNode;A(a,"destroy");Ja[a.index]=
|
||||
u;a.renderTo.removeAttribute("data-highcharts-chart");X(a);for(e=b.length;e--;)b[e]=b[e].destroy();for(e=c.length;e--;)c[e]=c[e].destroy();n("title,subtitle,chartBackground,plotBackground,plotBGImage,plotBorder,seriesGroup,clipRect,credits,pointer,scroller,rangeSelector,legend,resetZoomButton,tooltip,renderer".split(","),function(b){var c=a[b];c&&c.destroy&&(a[b]=c.destroy())});if(d)d.innerHTML="",X(d),f&&Oa(d);for(e in a)delete a[e]},isReadyToRender:function(){var a=this;return!V&&C==C.top&&v.readyState!==
|
||||
"complete"||ba&&!C.canvg?(ba?Mb.push(function(){a.firstRender()},a.options.global.canvasToolsURL):v.attachEvent("onreadystatechange",function(){v.detachEvent("onreadystatechange",a.firstRender);v.readyState==="complete"&&a.firstRender()}),!1):!0},firstRender:function(){var a=this,b=a.options,c=a.callback;if(a.isReadyToRender())a.getContainer(),A(a,"init"),a.resetMargins(),a.setChartSize(),a.propFromSeries(),a.getAxes(),n(b.series||[],function(b){a.initSeries(b)}),a.linkSeries(),A(a,"beforeRender"),
|
||||
a.pointer=new Za(a,b),a.render(),a.renderer.draw(),c&&c.apply(a,[a]),n(a.callbacks,function(b){b.apply(a,[a])}),a.cloneRenderTo(!0),A(a,"load")},splashArray:function(a,b){var c=b[a],c=S(c)?c:[c,c,c,c];return[o(b[a+"Top"],c[0]),o(b[a+"Right"],c[1]),o(b[a+"Bottom"],c[2]),o(b[a+"Left"],c[3])]}};eb.prototype.callbacks=[];var xb=Highcharts.CenteredSeriesMixin={getCenter:function(){var a=this.options,b=this.chart,c=2*(a.slicedOffset||0),d,e=b.plotWidth-2*c,f=b.plotHeight-2*c,b=a.center,a=[o(b[0],"50%"),
|
||||
|
@ -1,5 +1,6 @@
|
||||
// if on api subdomain, redirect
|
||||
// if on api subdomain except for charts, redirect
|
||||
var wloc = window.location.toString();
|
||||
if (wloc.indexOf('api') != -1 && wloc.indexOf('api') < 10) {
|
||||
if (wloc.indexOf('api') !== -1 && wloc.indexOf('api') < 10 && wloc.indexOf('charts') === -1) {
|
||||
window.location = wloc.replace('api', 'www');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,11 +13,11 @@ function getDimensions(element) {
|
||||
}
|
||||
|
||||
function updateChart(index,
|
||||
postUpdate,
|
||||
width,
|
||||
height,
|
||||
channelId,
|
||||
newOptionsSave) {
|
||||
postUpdate,
|
||||
width,
|
||||
height,
|
||||
channelId,
|
||||
newOptionsSave) {
|
||||
// default width and height
|
||||
var width = width;
|
||||
var height = height;
|
||||
@ -26,52 +26,52 @@ function updateChart(index,
|
||||
var iframe = $('#iframe' + index).attr("default_src");
|
||||
|
||||
if (!iframe) {
|
||||
iframe = $('#iframe' + index).attr('src');
|
||||
iframe = $('#iframe' + index).attr('src');
|
||||
}
|
||||
|
||||
src = iframe.split('?')[0];
|
||||
// if not a line chart, a timeslice should be present or set timescale=30
|
||||
if ($('#type_' + index).val() != 'line') {
|
||||
if ($('#timescale_' + index).val().length == 0 && $('#average_' + index).val().length == 0 && $('#median_' + index).val().length == 0 && $('#sum_' + index).val().length == 0) {
|
||||
$('#timescale_' + index).val(30);
|
||||
}
|
||||
if ($('#timescale_' + index).val().length == 0 && $('#average_' + index).val().length == 0 && $('#median_' + index).val().length == 0 && $('#sum_' + index).val().length == 0) {
|
||||
$('#timescale_' + index).val(30);
|
||||
}
|
||||
}
|
||||
|
||||
// add inputs to array
|
||||
var inputs = [];
|
||||
$('.chart_options' + index).each(function() {
|
||||
var v = $(this).val();
|
||||
var id = $(this).attr('id');
|
||||
var tag = id.split("_")[0];
|
||||
var v = $(this).val();
|
||||
var id = $(this).attr('id');
|
||||
var tag = id.split("_")[0];
|
||||
|
||||
if (v.length > 0) { inputs.push([tag, v]); }
|
||||
});
|
||||
if (v.length > 0) { inputs.push([tag, v]); }
|
||||
});
|
||||
|
||||
// create querystring
|
||||
var qs = '';
|
||||
while (inputs.length > 0) {
|
||||
var p = inputs.pop();
|
||||
if (p[0] == 'width') { width = parseInt(p[1]); }
|
||||
if (p[0] == 'height') { height = parseInt(p[1]); }
|
||||
var p = inputs.pop();
|
||||
if (p[0] == 'width') { width = parseInt(p[1]); }
|
||||
if (p[0] == 'height') { height = parseInt(p[1]); }
|
||||
|
||||
// don't add type=line to querystring, it's the default value
|
||||
if (!(p[0] == 'type' && p[1] == 'line')) {
|
||||
qs += '&' + p[0] + '=' + encodeURIComponent(p[1]);
|
||||
}
|
||||
// don't add type=line to querystring, it's the default value
|
||||
if (!(p[0] == 'type' && p[1] == 'line')) {
|
||||
qs += '&' + p[0] + '=' + encodeURIComponent(p[1]);
|
||||
}
|
||||
}
|
||||
// if querystring exists, add it to src
|
||||
if (qs.length > 0) { src += '?' + qs.substring(1); }
|
||||
|
||||
// save chart options to database
|
||||
if (postUpdate && index > 0 && newOptionsSave) {
|
||||
$.update("/channels/" + channelId + "/charts/" + index,
|
||||
{
|
||||
newOptions : { options: qs }
|
||||
} );
|
||||
$.update("/channels/" + channelId + "/charts/" + index,
|
||||
{
|
||||
newOptions : { options: qs }
|
||||
} );
|
||||
}
|
||||
else if (postUpdate && index > 0) {
|
||||
$.update("/channels/" + channelId + "/charts/" + index,
|
||||
{ options: qs } );
|
||||
$.update("/channels/" + channelId + "/charts/" + index,
|
||||
{ options: qs } );
|
||||
}
|
||||
|
||||
// set embed code
|
||||
@ -90,9 +90,9 @@ function updateSelectValues() {
|
||||
|
||||
function setupChartForm(channelIndex) {
|
||||
return function(index, value) {
|
||||
if (value.length > 0) {
|
||||
$('#' + value.split('=')[0] + "_" + channelIndex).val(decodeURIComponent(value.split('=')[1]));
|
||||
}
|
||||
if (value.length > 0) {
|
||||
$('#' + value.split('=')[0] + "_" + channelIndex).val(decodeURIComponent(value.split('=')[1]));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -107,52 +107,52 @@ function setupColumns(current_user, channel_id)
|
||||
|
||||
function createWindowsWithData (data, current_user, channel_id, colName) {
|
||||
|
||||
for (var i in data) {
|
||||
//each array element has a single chart object as an associative array with the type as the key
|
||||
// so I need to iterate over a array with size=1 to get a string with the window type
|
||||
for (var type in data[i]) {
|
||||
var wtype = type;
|
||||
}
|
||||
if (data[i].chart_window) window = data[i].chart_window;
|
||||
if (data[i].plugin_window) window = data[i].plugin_window;
|
||||
if (data[i].portlet_window) window = data[i].portlet_window;
|
||||
for (var i in data) {
|
||||
//each array element has a single chart object as an associative array with the type as the key
|
||||
// so I need to iterate over a array with size=1 to get a string with the window type
|
||||
for (var type in data[i]) {
|
||||
var wtype = type;
|
||||
}
|
||||
if (data[i].chart_window) window = data[i].chart_window;
|
||||
if (data[i].plugin_window) window = data[i].plugin_window;
|
||||
if (data[i].portlet_window) window = data[i].portlet_window;
|
||||
|
||||
if (window == "undefined")
|
||||
if (window == "undefined")
|
||||
var window = (data[i].portlet_window) ? data[i].portlet_window : data[i].chart_window;
|
||||
colId = window.col;
|
||||
title = window.title;
|
||||
colId = window.col;
|
||||
title = window.title;
|
||||
|
||||
var content = window.html;
|
||||
if (data[i].chart_window) {
|
||||
var windowId = window.id;
|
||||
$("body").append("<div id='chartConfig"+windowId+"'></div>");
|
||||
var content = window.html;
|
||||
if (data[i].chart_window) {
|
||||
var windowId = window.id;
|
||||
$("body").append("<div id='chartConfig"+windowId+"'></div>");
|
||||
}
|
||||
var portlet = addWindow(colName, colId, window.id, wtype, title, content);
|
||||
portlet.each ( decoratePortlet(current_user) ) ;
|
||||
var portlet = addWindow(colName, colId, window.id, wtype, title, content);
|
||||
portlet.each ( decoratePortlet(current_user) ) ;
|
||||
|
||||
portlet.find( ".ui-toggle" ).click( uiToggleClick );
|
||||
portlet.find( ".ui-view" ).click( uiViewClick (channel_id) );
|
||||
portlet.find( ".ui-edit" ).click( uiEditClick (channel_id) );
|
||||
portlet.find( ".ui-close" ).click( uiCloseClick (channel_id) );
|
||||
}
|
||||
portlet.find( ".ui-toggle" ).click( uiToggleClick );
|
||||
portlet.find( ".ui-view" ).click( uiViewClick (channel_id) );
|
||||
portlet.find( ".ui-edit" ).click( uiEditClick (channel_id) );
|
||||
portlet.find( ".ui-close" ).click( uiCloseClick (channel_id) );
|
||||
}
|
||||
}
|
||||
var createWindows = function (current_user, channel_id, colName) {
|
||||
return function(data) {
|
||||
createWindowsWithData(data, current_user, channel_id, colName);
|
||||
createWindowsWithData(data, current_user, channel_id, colName);
|
||||
};
|
||||
}
|
||||
|
||||
function addWindow(colName, colId, windowId, wtype, title, content) {
|
||||
$("#"+colName+"_dialog"+colId).append('<div class="portlet ui-widget ui-widget-content ui-helper-clearfix ui-corner-all" ' +
|
||||
'id="portlet_' + windowId +
|
||||
'"><div class="portlet-header wtype wtype-'+ wtype
|
||||
+ ' ui-widget-header ui-corner-all">' + title +
|
||||
'</div><div class="portlet-content">'+content+'</div>') ;
|
||||
'id="portlet_' + windowId +
|
||||
'"><div class="portlet-header wtype wtype-'+ wtype
|
||||
+ ' ui-widget-header ui-corner-all">' + title +
|
||||
'</div><div class="portlet-content">'+content+'</div>') ;
|
||||
|
||||
if ($("#portlet_"+windowId).length > 1) {
|
||||
throw "Portlet count doesn't match what's expected";
|
||||
throw "Portlet count doesn't match what's expected";
|
||||
} else {
|
||||
return $("#portlet_"+windowId);
|
||||
return $("#portlet_"+windowId);
|
||||
}
|
||||
|
||||
}
|
||||
@ -161,22 +161,22 @@ function addWindow(colName, colId, windowId, wtype, title, content) {
|
||||
var updatePortletPositions = function( current_user, channel_id) {
|
||||
return function() {
|
||||
if (current_user) {
|
||||
var result = $(this).sortable('serialize');
|
||||
colId = $(this).attr('id').charAt($(this).attr('id').length - 1);
|
||||
portletArray = getPortletArray(result);
|
||||
jsonResult = {
|
||||
"col" : colId,
|
||||
"positions" : portletArray
|
||||
} ;
|
||||
var result = $(this).sortable('serialize');
|
||||
colId = $(this).attr('id').charAt($(this).attr('id').length - 1);
|
||||
portletArray = getPortletArray(result);
|
||||
jsonResult = {
|
||||
"col" : colId,
|
||||
"positions" : portletArray
|
||||
} ;
|
||||
|
||||
if (portletArray.length > 0) {
|
||||
$.ajax({
|
||||
type: 'PUT',
|
||||
url: '../channels/' + channel_id + '/windows',
|
||||
data: {_method:'PUT', page : JSON.stringify(jsonResult ) },
|
||||
dataType: 'json'
|
||||
});
|
||||
}
|
||||
if (portletArray.length > 0) {
|
||||
$.ajax({
|
||||
type: 'PUT',
|
||||
url: '../channels/' + channel_id + '/windows',
|
||||
data: {_method:'PUT', page : JSON.stringify(jsonResult ) },
|
||||
dataType: 'json'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -184,31 +184,31 @@ var updatePortletPositions = function( current_user, channel_id) {
|
||||
function sortColumnSetup(current_user, channel_id) {
|
||||
|
||||
$( ".column" ).sortable({
|
||||
opacity: 0.6,
|
||||
helper: function( event ) {
|
||||
return $("<div class='ui-widget-header'>Drop to re-position</div>");
|
||||
},
|
||||
connectWith: ".column",
|
||||
update: updatePortletPositions(current_user, channel_id)
|
||||
});
|
||||
opacity: 0.6,
|
||||
helper: function( event ) {
|
||||
return $("<div class='ui-widget-header'>Drop to re-position</div>");
|
||||
},
|
||||
connectWith: ".column",
|
||||
update: updatePortletPositions(current_user, channel_id)
|
||||
});
|
||||
}
|
||||
var decoratePortlet = function (current_user) {
|
||||
return function() {
|
||||
var portletHeader = $(this).find( ".portlet-header") ;
|
||||
portletHeader.append( "<span id='commentBtn' class='ui-view ui-icon ui-icon-comment'></span>");
|
||||
var portletHeader = $(this).find( ".portlet-header") ;
|
||||
portletHeader.append( "<span id='commentBtn' class='ui-view ui-icon ui-icon-comment'></span>");
|
||||
|
||||
thisObject = $(this);
|
||||
if (current_user == "true") {
|
||||
// Use feature Rollout here - needs to be implemented for this user, and this channel needs to belong to this user.
|
||||
thisObject.find('.wtype').prepend( "<span id='minusBtn' class='ui-toggle ui-icon ui-icon-minusthick'></span>");
|
||||
thisObject.find(".wtype-chart_window").append("<span id='pencilBtn' class='ui-edit ui-icon ui-icon-pencil'></span>");
|
||||
thisObject.find(".wtype").append("<span id='closeBtn' class='ui-close ui-icon ui-icon-close'></span>");
|
||||
thisObject.find(".portlet-header").css("cursor","move");
|
||||
}
|
||||
else {
|
||||
$(".column").sortable({ disabled:true });
|
||||
}
|
||||
return $(this).attr("id");
|
||||
thisObject = $(this);
|
||||
if (current_user == "true") {
|
||||
// Use feature Rollout here - needs to be implemented for this user, and this channel needs to belong to this user.
|
||||
thisObject.find('.wtype').prepend( "<span id='minusBtn' class='ui-toggle ui-icon ui-icon-minusthick'></span>");
|
||||
thisObject.find(".wtype-chart_window").append("<span id='pencilBtn' class='ui-edit ui-icon ui-icon-pencil'></span>");
|
||||
thisObject.find(".wtype").append("<span id='closeBtn' class='ui-close ui-icon ui-icon-close'></span>");
|
||||
thisObject.find(".portlet-header").css("cursor","move");
|
||||
}
|
||||
else {
|
||||
$(".column").sortable({ disabled:true });
|
||||
}
|
||||
return $(this).attr("id");
|
||||
}
|
||||
}
|
||||
function getPortletArray(data) {
|
||||
@ -218,8 +218,8 @@ function getPortletArray(data) {
|
||||
|
||||
for (i in inputArray) {
|
||||
|
||||
val = inputArray[i].split("=")[1] ;
|
||||
resultArray.push(val);
|
||||
val = inputArray[i].split("=")[1] ;
|
||||
resultArray.push(val);
|
||||
}
|
||||
|
||||
return resultArray;
|
||||
@ -228,63 +228,63 @@ function getPortletArray(data) {
|
||||
|
||||
var uiEditClick = function (channel_id) {
|
||||
return function() {
|
||||
var id = $( this ).parents( ".portlet:first" ).attr("id").substring(8);
|
||||
var id = $( this ).parents( ".portlet:first" ).attr("id").substring(8);
|
||||
|
||||
var options = "";
|
||||
$("#chartConfig"+id).load("/channels/"+channel_id+"/charts/"+id+"/edit",
|
||||
function() {
|
||||
options = $("#chartOptions"+id).html();
|
||||
var options = "";
|
||||
$("#chartConfig"+id).load("/channels/"+channel_id+"/charts/"+id+"/edit",
|
||||
function() {
|
||||
options = $("#chartOptions"+id).html();
|
||||
|
||||
if (options != "undefined" && options.length >2) {
|
||||
$.each((options.split('&')), setupChartForm( id ));
|
||||
}
|
||||
$("#button"+id).click( function() {
|
||||
updateChart(id, true, 450, 250, channel_id, true);
|
||||
$("#chartConfig"+id).dialog("close");
|
||||
if (options != "undefined" && options.length >2) {
|
||||
$.each((options.split('&')), setupChartForm( id ));
|
||||
}
|
||||
$("#button"+id).click( function() {
|
||||
updateChart(id, true, 450, 250, channel_id, true);
|
||||
$("#chartConfig"+id).dialog("close");
|
||||
|
||||
});
|
||||
})
|
||||
.dialog({ title:"Chart Options", modal: true, resizable: false, width: 500, dialogClass: "dev-info-dialog" });
|
||||
});
|
||||
})
|
||||
.dialog({ title:"Chart Options", modal: true, resizable: false, width: 500, dialogClass: "dev-info-dialog" });
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
var uiViewClick = function (channel_id) {
|
||||
return function() {
|
||||
var x = $( this ).parents( ".portlet:first" ).find( ".portlet-content" ).offset().left;
|
||||
var y = $( this ).parents( ".portlet:first" ).find( ".portlet-content" ).offset().top;
|
||||
var id = $( this ).parents( ".portlet:first" ).attr("id").substring(8);
|
||||
var x = $( this ).parents( ".portlet:first" ).find( ".portlet-content" ).offset().left;
|
||||
var y = $( this ).parents( ".portlet:first" ).find( ".portlet-content" ).offset().top;
|
||||
var id = $( this ).parents( ".portlet:first" ).attr("id").substring(8);
|
||||
|
||||
$("body").append('<div id="iframepopup'+id+'" style="display:none">' +
|
||||
'<div id="iframeinner'+id+'"style="font-size:1.2em;overflow:auto;height:115px;background-color:white">' +
|
||||
'</div></div>');
|
||||
$("body").append('<div id="iframepopup'+id+'" style="display:none">' +
|
||||
'<div id="iframeinner'+id+'"style="font-size:1.2em;overflow:auto;height:115px;background-color:white">' +
|
||||
'</div></div>');
|
||||
|
||||
$.get("/channels/"+channel_id+"/windows/"+id+"/iframe",
|
||||
function(response) {
|
||||
var display = response.replace(/id=\"iframe[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?\"/, "" );
|
||||
$("#iframeinner"+id).text(display);
|
||||
}
|
||||
);
|
||||
$.get("/channels/"+channel_id+"/windows/"+id+"/iframe",
|
||||
function(response) {
|
||||
var display = response.replace(/id=\"iframe[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?[0-9]?\"/, "" );
|
||||
$("#iframeinner"+id).text(display);
|
||||
}
|
||||
);
|
||||
|
||||
$("#iframepopup"+id).dialog({
|
||||
resizable:false,
|
||||
width: "300px",
|
||||
position:[x+200,y-200],
|
||||
title: "Chart Iframe",
|
||||
dialogClass: "dev-info-dialog"
|
||||
});
|
||||
$("#iframepopup"+id).dialog({
|
||||
resizable:false,
|
||||
width: "300px",
|
||||
position:[x+200,y-200],
|
||||
title: "Chart Iframe",
|
||||
dialogClass: "dev-info-dialog"
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
var uiCloseClick = function (channel_id) {
|
||||
return function() {
|
||||
var id = $( this ).parents( ".portlet:first" ).attr("id").substring(8);
|
||||
var portlet = $( this ).parents( ".portlet:first" ) ;
|
||||
$.update("/channels/"+channel_id+"/windows/"+id+"/hide" ,
|
||||
function(response) {
|
||||
portlet.hide("drop", function(){
|
||||
portlet.remove();});
|
||||
}) ;
|
||||
var id = $( this ).parents( ".portlet:first" ).attr("id").substring(8);
|
||||
var portlet = $( this ).parents( ".portlet:first" ) ;
|
||||
$.update("/channels/"+channel_id+"/windows/"+id+"/hide" ,
|
||||
function(response) {
|
||||
portlet.hide("drop", function(){
|
||||
portlet.remove();});
|
||||
}) ;
|
||||
}
|
||||
}
|
||||
|
||||
|
17
app/assets/stylesheets/active_admin.css.scss
Normal file
@ -0,0 +1,17 @@
|
||||
// SASS variable overrides must be declared before loading up Active Admin's styles.
|
||||
//
|
||||
// To view the variables that Active Admin provides, take a look at
|
||||
// `app/assets/stylesheets/active_admin/mixins/_variables.css.scss` in the
|
||||
// Active Admin source.
|
||||
//
|
||||
// For example, to change the sidebar width:
|
||||
// $sidebar-width: 242px;
|
||||
|
||||
// Active Admin's got SASS!
|
||||
@import "active_admin/mixins";
|
||||
@import "active_admin/base";
|
||||
|
||||
// Overriding any non-variable SASS must be done after the fact.
|
||||
// For example, to change the default status-tag color:
|
||||
//
|
||||
// .status_tag { background: #6090DB; }
|
@ -3,7 +3,7 @@ class ApplicationController < ActionController::Base
|
||||
# include all helpers for controllers
|
||||
helper :all
|
||||
# include these helper methods for views
|
||||
helper_method :current_user_session, :current_user, :logged_in?, :is_admin?, :get_header_value, :to_bytes
|
||||
helper_method :current_user_session, :current_user, :logged_in?, :get_header_value, :to_bytes
|
||||
protect_from_forgery
|
||||
before_filter :allow_cross_domain_access, :set_variables
|
||||
before_filter :configure_permitted_parameters, if: :devise_controller?
|
||||
@ -47,8 +47,14 @@ class ApplicationController < ActionController::Base
|
||||
params[:sum] = '1440' if params[:sum] == 'daily'
|
||||
end
|
||||
|
||||
# change default devise sign_in page
|
||||
def after_sign_in_path_for(resource); channels_path; end
|
||||
# change default devise sign_in page; make admins sign in work correctly
|
||||
def after_sign_in_path_for(resource)
|
||||
if resource.is_a?(AdminUser)
|
||||
admin_dashboard_path
|
||||
else
|
||||
channels_path
|
||||
end
|
||||
end
|
||||
|
||||
# get the locale, but don't fail if header value doesn't exist
|
||||
def get_locale
|
||||
@ -106,15 +112,6 @@ class ApplicationController < ActionController::Base
|
||||
true if current_user
|
||||
end
|
||||
|
||||
# check that user's email address matches admin
|
||||
def is_admin?
|
||||
current_user.present? && ADMIN_EMAILS.include?(current_user.email)
|
||||
end
|
||||
|
||||
def set_admin_menu
|
||||
@menu = 'admin'
|
||||
end
|
||||
|
||||
# converts a string to a byte string for c output
|
||||
def to_bytes(input, separator='.', prefix='')
|
||||
return '' if input == nil
|
||||
@ -160,7 +157,7 @@ class ApplicationController < ActionController::Base
|
||||
end
|
||||
|
||||
def require_admin
|
||||
unless current_user && is_admin?
|
||||
unless current_admin_user.present?
|
||||
render :nothing => true, :status => 403 and return
|
||||
false
|
||||
end
|
||||
@ -194,8 +191,10 @@ class ApplicationController < ActionController::Base
|
||||
end
|
||||
|
||||
# domain for the api
|
||||
def api_domain
|
||||
(Rails.env == 'production') ? API_DOMAIN : domain
|
||||
def api_domain(ssl=false)
|
||||
output = (Rails.env == 'production') ? API_DOMAIN : domain
|
||||
output = output.sub(/http:/, 'https:') if ssl == true
|
||||
return output
|
||||
end
|
||||
|
||||
# ssl domain for the api
|
||||
|
@ -55,8 +55,8 @@ class ChartsController < ApplicationController
|
||||
params[:bgcolor] = fix_color(params[:bgcolor])
|
||||
|
||||
# set ssl
|
||||
@ssl = (get_header_value('x_ssl') == 'true')
|
||||
@domain = domain(@ssl)
|
||||
ssl = (get_header_value('x_ssl') == 'true')
|
||||
@domain = domain(ssl)
|
||||
|
||||
# should data be pushed off the end in dynamic chart
|
||||
@push = (params[:push] and params[:push] == 'false') ? false : true
|
||||
|
16
app/controllers/passwords_controller.rb
Normal file
@ -0,0 +1,16 @@
|
||||
class SessionsController < Devise::SessionsController
|
||||
before_filter :fix_params, :only => :create
|
||||
|
||||
# don't modify default devise controllers
|
||||
def create; super; end
|
||||
def new; super; end
|
||||
|
||||
private
|
||||
|
||||
# fixes password reset params so that devise config.reset_password_keys can be set to email for activeadmin
|
||||
def fix_params
|
||||
params[:user][:login] = params[:user][:email]
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -1,5 +1,5 @@
|
||||
class PipesController < ApplicationController
|
||||
before_filter :require_admin, :set_admin_menu
|
||||
before_filter :require_admin
|
||||
|
||||
def index
|
||||
@pipes = Pipe.paginate :page => params[:page], :order => 'created_at DESC'
|
||||
@ -14,3 +14,4 @@ class PipesController < ApplicationController
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
@ -4,7 +4,7 @@ class RegistrationsController < Devise::RegistrationsController
|
||||
|
||||
# use defaults from devise
|
||||
def new; super; end
|
||||
def new; super; end
|
||||
def edit; super; end
|
||||
def create; super; end
|
||||
|
||||
private
|
||||
|
2
app/helpers/admin_helper.rb
Normal file
@ -0,0 +1,2 @@
|
||||
module AdminHelper
|
||||
end
|
18
app/models/admin_user.rb
Normal file
@ -0,0 +1,18 @@
|
||||
class AdminUser < ActiveRecord::Base
|
||||
# Include default devise modules. Others available are:
|
||||
# :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable
|
||||
devise :database_authenticatable,
|
||||
:recoverable, :rememberable, :trackable, :validatable
|
||||
|
||||
attr_accessor :login
|
||||
|
||||
protected
|
||||
|
||||
def self.find_for_database_authentication(warden_conditions)
|
||||
conditions = warden_conditions.dup
|
||||
login = conditions.delete(:login)
|
||||
where(conditions).where(["lower(email) = :value", { :value => login.strip.downcase }]).first
|
||||
end
|
||||
|
||||
end
|
||||
|
4
app/views/admin/useful_links/_index.html.erb
Normal file
@ -0,0 +1,4 @@
|
||||
<%= link_to 'List Email Addresses', admin_emails_path %>
|
||||
<br><br>
|
||||
<%= link_to 'List Users by Day (CSV)', admin_signups_path(:format => :csv) %>
|
||||
|
4
app/views/admin/users/emails.html.erb
Normal file
@ -0,0 +1,4 @@
|
||||
<% @users.each do |u| %>
|
||||
<%= u.email %><br>
|
||||
<% end %>
|
||||
|
2
app/views/admin/users/signups.csv.erb
Normal file
@ -0,0 +1,2 @@
|
||||
<%= CSV.generate_line @csv_headers %><% @days.each do |day| %><% row = [] %><% @csv_headers.each do |attr| %><% row.push(day.to_json) %><% end %><%= CSV.generate_line(day).html_safe %><% end %>
|
||||
|
@ -45,7 +45,7 @@
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% if is_admin? %>
|
||||
<% if current_admin_user.present? %>
|
||||
<div class="apps">
|
||||
<%= link_to scheduled_thinghttps_path do %>
|
||||
<%= image_tag 'scheduled_thinghttp.png', :size => '104x104' %>
|
||||
|
@ -41,7 +41,7 @@
|
||||
<%= d.submit t(:channel_create), :class => 'btn btn-primary' %>
|
||||
<% end %>
|
||||
|
||||
<% if is_admin? %>
|
||||
<% if current_admin_user.present? %>
|
||||
|
||||
<br><br><br>
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
|
||||
<%= javascript_include_tag 'application' %>
|
||||
|
||||
<script type="text/javascript">
|
||||
@ -11,10 +11,10 @@
|
||||
|
||||
// converts date format from JSON
|
||||
function getChartDate(d) {
|
||||
// get the data using javascript's date object (year, month, day, hour, minute, second)
|
||||
// months in javascript start at 0, so remember to subtract 1 when specifying the month
|
||||
// offset in minutes is converted to milliseconds and subtracted so that chart's x-axis is correct
|
||||
return Date.UTC(d.substring(0,4), d.substring(5,7)-1, d.substring(8,10), d.substring(11,13), d.substring(14,16), d.substring(17,19)) - (myOffset * 60000);
|
||||
// get the data using javascript's date object (year, month, day, hour, minute, second)
|
||||
// months in javascript start at 0, so remember to subtract 1 when specifying the month
|
||||
// offset in minutes is converted to milliseconds and subtracted so that chart's x-axis is correct
|
||||
return Date.UTC(d.substring(0,4), d.substring(5,7)-1, d.substring(8,10), d.substring(11,13), d.substring(14,16), d.substring(17,19)) - (myOffset * 60000);
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
@ -26,61 +26,51 @@
|
||||
var last_date;
|
||||
|
||||
// get the data with a webservice call
|
||||
|
||||
$.getJSON('<%= "#{@domain}channels/#{params[:channel_id]}/field/#{params[:id]}.json?callback=?&offset=0#{@qs}" %>', function(data) {
|
||||
|
||||
// if no access
|
||||
if (data == '-1') {
|
||||
$('#chart-container').append('<%= t(:chart_no_access) %>');
|
||||
}
|
||||
if (data == '-1') { $('#chart-container').append('<%= t(:chart_no_access) %>'); }
|
||||
|
||||
// iterate through each feed
|
||||
$.each(data.feeds, function() {
|
||||
var p = new Highcharts.Point();
|
||||
// set the proper values
|
||||
var v = this.field<%= params[:id] %>;
|
||||
p.x = getChartDate(this.created_at);
|
||||
p.y = parseFloat(v);
|
||||
// add location if possible
|
||||
if (this.location) { p.name = this.location; }
|
||||
// if a numerical value exists add it
|
||||
if (!isNaN(parseInt(v))<% if params[:max] %> && p.y <= <%= params[:max]%><% end %><% if params[:min] %> && p.y >= <%= params[:min]%><% end %>) { chartData.push(p); }
|
||||
});
|
||||
var p = new Highcharts.Point();
|
||||
// set the proper values
|
||||
var v = this.field<%= params[:id] %>;
|
||||
p.x = getChartDate(this.created_at);
|
||||
p.y = parseFloat(v);
|
||||
// add location if possible
|
||||
if (this.location) { p.name = this.location; }
|
||||
// if a numerical value exists add it
|
||||
if (!isNaN(parseInt(v))<% if params[:max] %> && p.y <= <%= params[:max]%><% end %><% if params[:min] %> && p.y >= <%= params[:min]%><% end %>) { chartData.push(p); }
|
||||
});
|
||||
|
||||
// specify the chart options
|
||||
var chartOptions = {
|
||||
chart: {
|
||||
chart: {
|
||||
renderTo: 'chart-container',
|
||||
defaultSeriesType: '<%= params[:type] ? "#{params[:type]}" : "line" %>',
|
||||
backgroundColor: '<%= params[:bgcolor] || "#ffffff" %>',
|
||||
events: {
|
||||
load: function() {
|
||||
//if dynamic and no "timeslice" options are set
|
||||
// GAK 02/16/2013 Let's try to add the last "average" slice if params[:average]
|
||||
|
||||
renderTo: 'chart-container',
|
||||
defaultSeriesType: '<%= params[:type] ? "#{params[:type]}" : "line" %>',
|
||||
backgroundColor: '<%= params[:bgcolor] || "#ffffff" %>',
|
||||
events: {
|
||||
load: function() {
|
||||
//if dynamic and no "timeslice" options are set
|
||||
// GAK 02/16/2013 Let's try to add the last "average" slice if params[:average]
|
||||
var url = '<%= "#{@domain}channels/#{params[:channel_id]}/feed/last.json?callback=?&offset=0&location=true#{@qs}" %>' ;
|
||||
if ("<%= params[:average] %>".length > 0) {
|
||||
url = '<%= "#{@domain}channels/#{params[:channel_id]}/feed/last_average.json?callback=?&offset=0&location=true&average=#{params[:average]}#{@qs}" %>' ;
|
||||
} else if ("<%= params[:median] %>".length > 0) {
|
||||
url = '<%= "#{@domain}channels/#{params[:channel_id]}/feed/last_median.json?callback=?&offset=0&location=true&median=#{params[:median]}#{@qs}" %>' ;
|
||||
} else if ("<%= params[:sum] %>".length > 0) {
|
||||
url = '<%= "#{@domain}channels/#{params[:channel_id]}/feed/last_sum.json?callback=?&offset=0&location=true&sum=#{params[:sum]}#{@qs}" %>' ;
|
||||
}
|
||||
|
||||
var url = '<%= "#{@domain}channels/#{params[:channel_id]}/feed/last.json?callback=?&offset=0&location=true#{@qs}" %>' ;
|
||||
if ("<%= params[:average] %>".length > 0) {
|
||||
url = '<%= "#{@domain}channels/#{params[:channel_id]}/feed/last_average.json?callback=?&offset=0&location=true&average=#{params[:average]}#{@qs}" %>' ;
|
||||
}
|
||||
else if ("<%= params[:median] %>".length > 0) {
|
||||
url = '<%= "#{@domain}channels/#{params[:channel_id]}/feed/last_median.json?callback=?&offset=0&location=true&median=#{params[:median]}#{@qs}" %>' ;
|
||||
}
|
||||
else if ("<%= params[:sum] %>".length > 0) {
|
||||
url = '<%= "#{@domain}channels/#{params[:channel_id]}/feed/last_sum.json?callback=?&offset=0&location=true&sum=#{params[:sum]}#{@qs}" %>' ;
|
||||
}
|
||||
|
||||
if ('true' === '<%= params[:dynamic] %>' && (
|
||||
'<%= params[:timescale] %>'.length < 1
|
||||
)) {
|
||||
// push data every 15 seconds
|
||||
|
||||
setInterval(function() {
|
||||
// get the data with a webservice call if we're just getting the last channel
|
||||
|
||||
$.getJSON(url, function(data) {
|
||||
// if data exists
|
||||
if (data && data.field<%= params[:id] %>) {
|
||||
if ('true' === '<%= params[:dynamic] %>' && ('<%= params[:timescale] %>'.length < 1)) {
|
||||
// push data every 15 seconds
|
||||
setInterval(function() {
|
||||
// get the data with a webservice call if we're just getting the last channel
|
||||
$.getJSON(url, function(data) {
|
||||
// if data exists
|
||||
if (data && data.field<%= params[:id] %>) {
|
||||
|
||||
var p = new Highcharts.Point();
|
||||
// set the proper values
|
||||
@ -92,7 +82,7 @@
|
||||
if (data.location) { p.name = data.location; }
|
||||
// get the last date if possible
|
||||
if (dynamicChart.series[0].data.length > 0) {
|
||||
last_date = dynamicChart.series[0].data[dynamicChart.series[0].data.length-1].x;
|
||||
last_date = dynamicChart.series[0].data[dynamicChart.series[0].data.length-1].x;
|
||||
}
|
||||
var shift = <%= (@push=='true') ? 'true' : 'false' %> ; //default for shift
|
||||
|
||||
@ -101,19 +91,17 @@
|
||||
var results = <%= (@results) ? @results : 60 %>;
|
||||
|
||||
if ( results && dynamicChart.series[0].data.length+1 >= results ) {
|
||||
shift = true ;
|
||||
shift = true ;
|
||||
}
|
||||
// if a numerical value exists and it is a new date, add it
|
||||
if (!isNaN(parseInt(v)) && (p.x != last_date)<% if params[:max] %> && p.y <= <%= params[:max]%><% end %><% if params[:min] %> && p.y >= <%= params[:min]%><% end %>) {
|
||||
dynamicChart.series[0].addPoint(p, true, shift);
|
||||
dynamicChart.series[0].addPoint(p, true, shift);
|
||||
}
|
||||
else {
|
||||
dynamicChart.series[0].data[dynamicChart.series[0].data.length-1].update(p);
|
||||
dynamicChart.series[0].data[dynamicChart.series[0].data.length-1].update(p);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
}, 15000);
|
||||
}
|
||||
@ -169,9 +157,9 @@
|
||||
enabled: false
|
||||
},
|
||||
series: [{
|
||||
name: data.channel.field<%= params[:id] %>
|
||||
}]
|
||||
};
|
||||
name: data.channel.field<%= params[:id] %>
|
||||
}]
|
||||
};
|
||||
|
||||
// add the data to the chart
|
||||
chartOptions.series[0].data = chartData;
|
||||
@ -184,14 +172,16 @@
|
||||
// draw the chart
|
||||
var dynamicChart = new Highcharts.Chart(chartOptions);
|
||||
|
||||
});
|
||||
}); // end getJSON ajax call
|
||||
|
||||
});
|
||||
}); // end document.ready
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body style='background-color: <%= params[:bgcolor] ? params[:bgcolor] : 'white' %>;'>
|
||||
<div id="chart-container" style="width: <%= params[:width] ? params[:width].to_i - 25 : @width.to_i - 25 %>px; height: <%= params[:height] ? params[:height].to_i - 25 : @height.to_i - 25 %>px;"></div>
|
||||
<div id="chart-container" style="width: <%= params[:width] ? params[:width].to_i - 25 : @width.to_i - 25 %>px; height: <%= params[:height] ? params[:height].to_i - 25 : @height.to_i - 25 %>px; display: table-cell; vertical-align: middle;">
|
||||
<%= image_tag 'ajax-loader.gif', :style => "margin: auto; display: block;" %>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
@ -10,11 +10,10 @@
|
||||
|
||||
<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post, :class => 'form-horizontal' }) do |f| %>
|
||||
<%= devise_error_messages! %>
|
||||
<input name='userlogin' class='userlogin' />
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 col-xs-3 control-label"><%= t(:email) %></label>
|
||||
<div class="col-sm-9 col-xs-9"><%= f.text_field :login, :class => 'form-control' %></div>
|
||||
<div class="col-sm-9 col-xs-9"><%= f.text_field :email, :class => 'form-control' %></div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -30,6 +29,6 @@
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
document.getElementById('user_login').focus();
|
||||
document.getElementById('user_email').focus();
|
||||
</script>
|
||||
|
||||
|
@ -34,6 +34,9 @@
|
||||
<li><%= link_to t(:profile_edit), edit_profile_path %></li>
|
||||
</ul>
|
||||
</li>
|
||||
<% if current_admin_user.present? %>
|
||||
<li><%= link_to t(:admin), "/admin" %></li>
|
||||
<% end %>
|
||||
|
||||
<% else %>
|
||||
<li <%= "class=active" if @menu == 'channels' %>><%= link_to t(:channels), public_channels_path %></li>
|
||||
|
240
config/initializers/active_admin.rb
Normal file
@ -0,0 +1,240 @@
|
||||
ActiveAdmin.setup do |config|
|
||||
|
||||
# == Site Title
|
||||
#
|
||||
# Set the title that is displayed on the main layout
|
||||
# for each of the active admin pages.
|
||||
#
|
||||
config.site_title = "Thingspeak"
|
||||
|
||||
# Set the link url for the title. For example, to take
|
||||
# users to your main site. Defaults to no link.
|
||||
#
|
||||
# config.site_title_link = "/"
|
||||
|
||||
# Set an optional image to be displayed for the header
|
||||
# instead of a string (overrides :site_title)
|
||||
#
|
||||
# Note: Aim for an image that's 21px high so it fits in the header.
|
||||
#
|
||||
# config.site_title_image = "logo.png"
|
||||
|
||||
# == Default Namespace
|
||||
#
|
||||
# Set the default namespace each administration resource
|
||||
# will be added to.
|
||||
#
|
||||
# eg:
|
||||
# config.default_namespace = :hello_world
|
||||
#
|
||||
# This will create resources in the HelloWorld module and
|
||||
# will namespace routes to /hello_world/*
|
||||
#
|
||||
# To set no namespace by default, use:
|
||||
# config.default_namespace = false
|
||||
#
|
||||
# Default:
|
||||
# config.default_namespace = :admin
|
||||
#
|
||||
# You can customize the settings for each namespace by using
|
||||
# a namespace block. For example, to change the site title
|
||||
# within a namespace:
|
||||
#
|
||||
# config.namespace :admin do |admin|
|
||||
# admin.site_title = "Custom Admin Title"
|
||||
# end
|
||||
#
|
||||
# This will ONLY change the title for the admin section. Other
|
||||
# namespaces will continue to use the main "site_title" configuration.
|
||||
|
||||
# == User Authentication
|
||||
#
|
||||
# Active Admin will automatically call an authentication
|
||||
# method in a before filter of all controller actions to
|
||||
# ensure that there is a currently logged in admin user.
|
||||
#
|
||||
# This setting changes the method which Active Admin calls
|
||||
# within the controller.
|
||||
config.authentication_method = :authenticate_admin_user!
|
||||
|
||||
# == User Authorization
|
||||
#
|
||||
# Active Admin will automatically call an authorization
|
||||
# method in a before filter of all controller actions to
|
||||
# ensure that there is a user with proper rights. You can use
|
||||
# CanCanAdapter or make your own. Please refer to documentation.
|
||||
# config.authorization_adapter = ActiveAdmin::CanCanAdapter
|
||||
|
||||
# You can customize your CanCan Ability class name here.
|
||||
# config.cancan_ability_class = "Ability"
|
||||
|
||||
# You can specify a method to be called on unauthorized access.
|
||||
# This is necessary in order to prevent a redirect loop which happens
|
||||
# because, by default, user gets redirected to Dashboard. If user
|
||||
# doesn't have access to Dashboard, he'll end up in a redirect loop.
|
||||
# Method provided here should be defined in application_controller.rb.
|
||||
# config.on_unauthorized_access = :access_denied
|
||||
|
||||
# == Current User
|
||||
#
|
||||
# Active Admin will associate actions with the current
|
||||
# user performing them.
|
||||
#
|
||||
# This setting changes the method which Active Admin calls
|
||||
# to return the currently logged in user.
|
||||
config.current_user_method = :current_admin_user
|
||||
|
||||
|
||||
# == Logging Out
|
||||
#
|
||||
# Active Admin displays a logout link on each screen. These
|
||||
# settings configure the location and method used for the link.
|
||||
#
|
||||
# This setting changes the path where the link points to. If it's
|
||||
# a string, the strings is used as the path. If it's a Symbol, we
|
||||
# will call the method to return the path.
|
||||
#
|
||||
# Default:
|
||||
config.logout_link_path = :destroy_admin_user_session_path
|
||||
|
||||
# This setting changes the http method used when rendering the
|
||||
# link. For example :get, :delete, :put, etc..
|
||||
#
|
||||
# Default:
|
||||
# config.logout_link_method = :get
|
||||
|
||||
|
||||
# == Root
|
||||
#
|
||||
# Set the action to call for the root path. You can set different
|
||||
# roots for each namespace.
|
||||
#
|
||||
# Default:
|
||||
# config.root_to = 'dashboard#index'
|
||||
|
||||
|
||||
# == Admin Comments
|
||||
#
|
||||
# This allows your users to comment on any resource registered with Active Admin.
|
||||
#
|
||||
# You can completely disable comments:
|
||||
# config.allow_comments = false
|
||||
#
|
||||
# You can disable the menu item for the comments index page:
|
||||
config.show_comments_in_menu = false
|
||||
#
|
||||
# You can change the name under which comments are registered:
|
||||
# config.comments_registration_name = 'AdminComment'
|
||||
|
||||
|
||||
# == Batch Actions
|
||||
#
|
||||
# Enable and disable Batch Actions
|
||||
#
|
||||
config.batch_actions = true
|
||||
|
||||
|
||||
# == Controller Filters
|
||||
#
|
||||
# You can add before, after and around filters to all of your
|
||||
# Active Admin resources and pages from here.
|
||||
#
|
||||
# config.before_filter :do_something_awesome
|
||||
|
||||
|
||||
# == Setting a Favicon
|
||||
#
|
||||
# config.favicon = '/assets/favicon.ico'
|
||||
|
||||
|
||||
# == Removing Breadcrumbs
|
||||
#
|
||||
# Breadcrumbs are enabled by default. You can customize them for individual
|
||||
# resources or you can disable them globally from here.
|
||||
#
|
||||
# config.breadcrumb = false
|
||||
|
||||
|
||||
# == Register Stylesheets & Javascripts
|
||||
#
|
||||
# We recommend using the built in Active Admin layout and loading
|
||||
# up your own stylesheets / javascripts to customize the look
|
||||
# and feel.
|
||||
#
|
||||
# To load a stylesheet:
|
||||
# config.register_stylesheet 'my_stylesheet.css'
|
||||
#
|
||||
# You can provide an options hash for more control, which is passed along to stylesheet_link_tag():
|
||||
# config.register_stylesheet 'my_print_stylesheet.css', :media => :print
|
||||
#
|
||||
# To load a javascript file:
|
||||
# config.register_javascript 'my_javascript.js'
|
||||
|
||||
|
||||
# == CSV options
|
||||
#
|
||||
# Set the CSV builder separator
|
||||
# config.csv_options = { :col_sep => ';' }
|
||||
#
|
||||
# Force the use of quotes
|
||||
# config.csv_options = { :force_quotes => true }
|
||||
|
||||
|
||||
# == Menu System
|
||||
#
|
||||
# You can add a navigation menu to be used in your application, or configure a provided menu
|
||||
config.namespace :admin do |admin|
|
||||
admin.build_menu :utility_navigation do |menu|
|
||||
admin.add_logout_button_to_menu menu
|
||||
end
|
||||
end
|
||||
|
||||
# If you wanted to add a static menu item to the default menu provided:
|
||||
#
|
||||
# config.namespace :admin do |admin|
|
||||
# admin.build_menu :default do |menu|
|
||||
# menu.add label: "My Great Website", url: "http://www.mygreatwebsite.com", html_options: { target: :blank }
|
||||
# end
|
||||
# end
|
||||
|
||||
|
||||
# == Download Links
|
||||
#
|
||||
# You can disable download links on resource listing pages,
|
||||
# or customize the formats shown per namespace/globally
|
||||
#
|
||||
# To disable/customize for the :admin namespace:
|
||||
#
|
||||
# config.namespace :admin do |admin|
|
||||
#
|
||||
# # Disable the links entirely
|
||||
# admin.download_links = false
|
||||
#
|
||||
# # Only show XML & PDF options
|
||||
# admin.download_links = [:xml, :pdf]
|
||||
#
|
||||
# # Enable/disable the links based on block
|
||||
# # (for example, with cancan)
|
||||
# admin.download_links = proc { can?(:view_download_links) }
|
||||
#
|
||||
# end
|
||||
|
||||
|
||||
# == Pagination
|
||||
#
|
||||
# Pagination is enabled by default for all resources.
|
||||
# You can control the default per page count for all resources here.
|
||||
#
|
||||
# config.default_per_page = 30
|
||||
|
||||
|
||||
# == Filters
|
||||
#
|
||||
# By default the index screen includes a “Filters” sidebar on the right
|
||||
# hand side with a filter for each attribute of the registered model.
|
||||
# You can enable or disable them for all resources here.
|
||||
#
|
||||
# config.filters = false
|
||||
|
||||
end
|
||||
|
@ -179,7 +179,7 @@ Devise.setup do |config|
|
||||
# ==> Configuration for :recoverable
|
||||
#
|
||||
# Defines which key will be used when recovering the password for an account
|
||||
config.reset_password_keys = [ :login ]
|
||||
config.reset_password_keys = [ :email ]
|
||||
|
||||
# Time interval you can reset your password with a reset password key.
|
||||
# Don't put a too small interval or your users won't have the time to
|
||||
|
4
config/initializers/kaminari.rb
Normal file
@ -0,0 +1,4 @@
|
||||
Kaminari.configure do |config|
|
||||
config.page_method_name = :per_page_kaminari
|
||||
end
|
||||
|
@ -1,5 +1,9 @@
|
||||
Thingspeak::Application.routes.draw do
|
||||
|
||||
# admin routes
|
||||
devise_for :admin_users, ActiveAdmin::Devise.config
|
||||
ActiveAdmin.routes(self)
|
||||
|
||||
# main data posts using this route
|
||||
match 'update', :to => 'channels#post_data', :via => ((GET_SUPPORT) ? [:get, :post] : :post)
|
||||
match 's/update', :to => 'channels#post_data', :via => [:get, :post]
|
||||
@ -180,16 +184,10 @@ Thingspeak::Application.routes.draw do
|
||||
|
||||
resources :apps, :only => ['index']
|
||||
|
||||
get 'admin', :to => 'admin#index', :as => 'admin'
|
||||
namespace :admin do
|
||||
resources :users
|
||||
resources :channels
|
||||
resources :twitter_accounts
|
||||
resources :thinghttps
|
||||
resources :devices
|
||||
resources :failedlogins
|
||||
resources :emails
|
||||
end
|
||||
# admin signups by day
|
||||
get 'admin/signups', :as => 'admin_signups', :to => 'admin/users#signups'
|
||||
# admin list of all email addresses
|
||||
get 'admin/emails', :as => 'admin_emails', :to => 'admin/users#emails'
|
||||
|
||||
# app shortcuts
|
||||
get 'apps/thingtweet', :to => 'thingtweets#index'
|
||||
|
49
db/migrate/20140320200306_devise_create_admin_users.rb
Normal file
@ -0,0 +1,49 @@
|
||||
class DeviseCreateAdminUsers < ActiveRecord::Migration
|
||||
def migrate(direction)
|
||||
super
|
||||
# Create a default user
|
||||
# AdminUser.create!(email: 'admin@example.com', password: 'password', password_confirmation: 'password') if direction == :up
|
||||
end
|
||||
|
||||
def change
|
||||
create_table(:admin_users) do |t|
|
||||
## Database authenticatable
|
||||
t.string :email, :null => false, :default => ""
|
||||
t.string :encrypted_password, :null => false, :default => ""
|
||||
|
||||
## Recoverable
|
||||
t.string :reset_password_token
|
||||
t.datetime :reset_password_sent_at
|
||||
|
||||
## Rememberable
|
||||
t.datetime :remember_created_at
|
||||
|
||||
## Trackable
|
||||
t.integer :sign_in_count, :default => 0, :null => false
|
||||
t.datetime :current_sign_in_at
|
||||
t.datetime :last_sign_in_at
|
||||
t.string :current_sign_in_ip
|
||||
t.string :last_sign_in_ip
|
||||
|
||||
## Confirmable
|
||||
# t.string :confirmation_token
|
||||
# t.datetime :confirmed_at
|
||||
# t.datetime :confirmation_sent_at
|
||||
# t.string :unconfirmed_email # Only if using reconfirmable
|
||||
|
||||
## Lockable
|
||||
# t.integer :failed_attempts, :default => 0, :null => false # Only if lock strategy is :failed_attempts
|
||||
# t.string :unlock_token # Only if unlock strategy is :email or :both
|
||||
# t.datetime :locked_at
|
||||
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
add_index :admin_users, :email, :unique => true
|
||||
add_index :admin_users, :reset_password_token, :unique => true
|
||||
# add_index :admin_users, :confirmation_token, :unique => true
|
||||
# add_index :admin_users, :unlock_token, :unique => true
|
||||
end
|
||||
end
|
||||
|
20
db/migrate/20140320200307_create_active_admin_comments.rb
Normal file
@ -0,0 +1,20 @@
|
||||
class CreateActiveAdminComments < ActiveRecord::Migration
|
||||
def self.up
|
||||
create_table :active_admin_comments do |t|
|
||||
t.string :namespace
|
||||
t.text :body
|
||||
t.string :resource_id, null: false, limit: 50
|
||||
t.string :resource_type, null: false, limit: 50
|
||||
t.references :author, polymorphic: true
|
||||
t.timestamps
|
||||
end
|
||||
add_index :active_admin_comments, [:namespace]
|
||||
add_index :active_admin_comments, [:author_type, :author_id]
|
||||
add_index :active_admin_comments, [:resource_type, :resource_id]
|
||||
end
|
||||
|
||||
def self.down
|
||||
drop_table :active_admin_comments
|
||||
end
|
||||
end
|
||||
|
35
db/schema.rb
@ -11,7 +11,40 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20140306013304) do
|
||||
ActiveRecord::Schema.define(version: 20140320200307) do
|
||||
|
||||
create_table "active_admin_comments", force: true do |t|
|
||||
t.string "namespace"
|
||||
t.text "body"
|
||||
t.string "resource_id", limit: 50, null: false
|
||||
t.string "resource_type", limit: 50, null: false
|
||||
t.integer "author_id"
|
||||
t.string "author_type"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
add_index "active_admin_comments", ["author_type", "author_id"], name: "index_active_admin_comments_on_author_type_and_author_id", using: :btree
|
||||
add_index "active_admin_comments", ["namespace"], name: "index_active_admin_comments_on_namespace", using: :btree
|
||||
add_index "active_admin_comments", ["resource_type", "resource_id"], name: "index_active_admin_comments_on_resource_type_and_resource_id", using: :btree
|
||||
|
||||
create_table "admin_users", force: true do |t|
|
||||
t.string "email", default: "", null: false
|
||||
t.string "encrypted_password", default: "", null: false
|
||||
t.string "reset_password_token"
|
||||
t.datetime "reset_password_sent_at"
|
||||
t.datetime "remember_created_at"
|
||||
t.integer "sign_in_count", default: 0, null: false
|
||||
t.datetime "current_sign_in_at"
|
||||
t.datetime "last_sign_in_at"
|
||||
t.string "current_sign_in_ip"
|
||||
t.string "last_sign_in_ip"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
|
||||
add_index "admin_users", ["email"], name: "index_admin_users_on_email", unique: true, using: :btree
|
||||
add_index "admin_users", ["reset_password_token"], name: "index_admin_users_on_reset_password_token", unique: true, using: :btree
|
||||
|
||||
create_table "api_keys", force: true do |t|
|
||||
t.string "api_key", limit: 16
|
||||
|
After Width: | Height: | Size: 716 B |
@ -0,0 +1 @@
|
||||
(function(){$(function(){var t;return $(document).on("focus",".datepicker:not(.hasDatepicker)",function(){var t,e;return t={dateFormat:"yy-mm-dd"},e=$(this).data("datepicker-options"),$(this).datepicker($.extend(t,e))}),$(".clear_filters_btn").click(function(){return window.location.search=""}),$(".dropdown_button").popover(),$(".filter_form").submit(function(){return $(this).find(":input").filter(function(){return""===this.value}).prop("disabled",!0)}),$(".filter_form_field.select_and_search select").change(function(){return $(this).siblings("input").prop({name:"q["+this.value+"]"})}),(t=$(".table_tools .batch_actions_selector")).length?t.next().css({width:"calc(100% - 10px - "+t.outerWidth()+"px)","float":"right"}):void 0})}).call(this);
|
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1006 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1004 B |
@ -0,0 +1,10 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" width="100px" height="87.5px" viewBox="0 0 100 87.5" style="enable-background:new 0 0 100 87.5;" xml:space="preserve">
|
||||
<path style="fill:#010101;" d="M12.5,6.25c0,3.455-2.795,6.25-6.25,6.25C2.795,12.5,0,9.705,0,6.25C0,2.795,2.795,0,6.25,0 C9.705,0,12.5,2.795,12.5,6.25z"/>
|
||||
<rect x="25" style="fill:#010101;" width="75" height="12.5"/>
|
||||
<path style="fill:#010101;" d="M12.5,56.25c0,3.455-2.795,6.25-6.25,6.25C2.795,62.5,0,59.705,0,56.25S2.795,50,6.25,50 C9.705,50,12.5,52.795,12.5,56.25z"/>
|
||||
<rect x="25" y="50" style="fill:#010101;" width="75" height="12.5"/>
|
||||
<path style="fill:#010101;" d="M12.5,31.25c0,3.455-2.795,6.25-6.25,6.25C2.795,37.5,0,34.705,0,31.25S2.795,25,6.25,25 C9.705,25,12.5,27.795,12.5,31.25z"/>
|
||||
<path style="fill:#010101;" d="M12.5,81.25c0,3.455-2.795,6.25-6.25,6.25C2.795,87.5,0,84.705,0,81.25S2.795,75,6.25,75 C9.705,75,12.5,77.795,12.5,81.25z"/>
|
||||
<rect x="25" y="25" style="fill:#010101;" width="75" height="12.5"/>
|
||||
<rect x="25" y="75" style="fill:#010101;" width="75" height="12.5"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" width="100px" height="63.62px" viewBox="0 0 100 63.62" enable-background="new 0 0 100 63.62" xml:space="preserve">
|
||||
<path d="M40.592,41.293V23.226c0-4.67,3.617-8.457,8.079-8.457h17.675v-4.307C66.346,4.685,61.868,0,56.35,0H9.996 C4.477,0,0,4.685,0,10.463v22.354c0,5.777,4.477,10.463,9.996,10.463h7.649c0,4.115,0,8.234,0,12.352 c0,0.682,0.936,1.162,1.422,0.59c3.645-4.314,7.287-8.627,10.933-12.941h10.825C40.677,42.641,40.592,41.979,40.592,41.293z"/>
|
||||
<path d="M45.178,26.205v20.168c0,4.211,3.263,7.627,7.289,7.627h19.21c2.658,3.145,5.313,6.289,7.97,9.434 c0.354,0.42,1.036,0.068,1.036-0.428c0-3.002,0-6.004,0-9.006h12.029c4.025,0,7.288-3.416,7.288-7.627V26.205 c0-4.212-3.263-7.629-7.288-7.629H52.467C48.441,18.576,45.178,21.992,45.178,26.205z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 881 B |
@ -0,0 +1,13 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" width="100px" height="100px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve">
|
||||
<g>
|
||||
<path fill="#000000" d="M24.666,2.5H5.334C3.769,2.5,2.5,3.769,2.5,5.334v19.331c0,1.565,1.269,2.834,2.834,2.834h19.331 c1.565,0,2.834-1.269,2.834-2.834V5.334C27.5,3.769,26.231,2.5,24.666,2.5z"/>
|
||||
<path fill="#000000" d="M59.704,2.5H40.373c-1.565,0-2.834,1.269-2.834,2.834v19.331c0,1.565,1.269,2.834,2.834,2.834h19.331 c1.565,0,2.835-1.269,2.835-2.834V5.334C62.539,3.769,61.27,2.5,59.704,2.5z"/>
|
||||
<path fill="#000000" d="M94.742,2.5h-19.33c-1.566,0-2.835,1.269-2.835,2.834v19.331c0,1.565,1.269,2.834,2.835,2.834h19.33 c1.566,0,2.836-1.269,2.836-2.834V5.334C97.578,3.769,96.309,2.5,94.742,2.5z"/>
|
||||
<path fill="#000000" d="M24.666,37.667H5.334c-1.565,0-2.834,1.269-2.834,2.834v19.331c0,1.565,1.269,2.834,2.834,2.834h19.331 c1.565,0,2.834-1.269,2.834-2.834V40.501C27.5,38.936,26.231,37.667,24.666,37.667z"/>
|
||||
<path fill="#000000" d="M59.704,37.667H40.373c-1.565,0-2.834,1.269-2.834,2.834v19.331c0,1.565,1.269,2.834,2.834,2.834h19.331 c1.565,0,2.835-1.269,2.835-2.834V40.501C62.539,38.936,61.27,37.667,59.704,37.667z"/>
|
||||
<path fill="#000000" d="M94.742,37.667h-19.33c-1.566,0-2.835,1.269-2.835,2.834v19.331c0,1.565,1.269,2.834,2.835,2.834h19.33 c1.566,0,2.836-1.269,2.836-2.834V40.501C97.578,38.936,96.309,37.667,94.742,37.667z"/>
|
||||
<path fill="#000000" d="M24.666,72.833H5.334c-1.565,0-2.834,1.269-2.834,2.835v19.33c0,1.566,1.269,2.834,2.834,2.834h19.331 c1.565,0,2.834-1.268,2.834-2.834v-19.33C27.5,74.102,26.231,72.833,24.666,72.833z"/>
|
||||
<path fill="#000000" d="M59.704,72.833H40.373c-1.565,0-2.834,1.269-2.834,2.835v19.33c0,1.566,1.269,2.834,2.834,2.834h19.331 c1.565,0,2.835-1.268,2.835-2.834v-19.33C62.539,74.102,61.27,72.833,59.704,72.833z"/>
|
||||
<path fill="#000000" d="M94.742,72.833h-19.33c-1.566,0-2.835,1.269-2.835,2.835v19.33c0,1.566,1.269,2.834,2.835,2.834h19.33 c1.566,0,2.836-1.268,2.836-2.834v-19.33C97.578,74.102,96.309,72.833,94.742,72.833z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.1 KiB |
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" width="100px" height="100px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve">
|
||||
<path d="M0,0v100h100V0H0z M93.164,39.662H66.55V25.469h2.396h24.219V39.662z M64.499,58.308H35.501V41.706h28.998V58.308z M35.501,39.662V25.469h2.389h24.219h2.39v14.193H35.501z M31.055,25.469h2.396v14.193H6.836V25.469H31.055z M33.451,41.706v16.602 H6.836V41.706H33.451z M6.836,60.352h26.615v16.575H6.836V60.352z M35.501,60.352h28.998v16.575H35.501V60.352z M66.55,60.352 h26.614v16.575H66.55V60.352z M66.55,58.308V41.706h26.614v16.602H66.55z M6.836,93.164v-14.18h26.615v14.18H6.836z M35.501,93.164 v-14.18h28.998v14.18H35.501z M66.55,78.984h26.614v14.18H66.55V78.984z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 815 B |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 70 B |
After Width: | Height: | Size: 70 B |
After Width: | Height: | Size: 220 B |
BIN
public/assets/ajax-loader-02917e3c114fd83f5c4c17953aa87e83.gif
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
public/assets/application-0b135d70dfcec58a528db9562b0ccf06.js.gz
Normal file
BIN
public/assets/application-27fa9ecfb64199c44a5aa35e88c13270.js.gz
Normal file
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 180 B |
After Width: | Height: | Size: 178 B |
After Width: | Height: | Size: 120 B |
After Width: | Height: | Size: 105 B |
After Width: | Height: | Size: 111 B |
After Width: | Height: | Size: 110 B |
After Width: | Height: | Size: 119 B |
After Width: | Height: | Size: 101 B |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 4.3 KiB |
11
test/fixtures/admin_users.yml
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
|
||||
|
||||
# This model initially had no columns defined. If you add columns to the
|
||||
# model remove the '{}' from the fixture names and add the columns immediately
|
||||
# below each fixture, per the syntax in the comments below
|
||||
#
|
||||
one: {}
|
||||
# column: value
|
||||
#
|
||||
two: {}
|
||||
# column: value
|
7
test/models/admin_user_test.rb
Normal file
@ -0,0 +1,7 @@
|
||||
require 'test_helper'
|
||||
|
||||
class AdminUserTest < ActiveSupport::TestCase
|
||||
# test "the truth" do
|
||||
# assert true
|
||||
# end
|
||||
end
|