rollout_admin 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +23 -0
- data/Rakefile +40 -0
- data/app/assets/images/rollout_admin/head_bg.jpg +0 -0
- data/app/assets/images/rollout_admin/icon_todos50x50.png +0 -0
- data/app/assets/images/rollout_admin/main_bg.jpg +0 -0
- data/app/assets/javascripts/rollout_admin/admin.js.erb +150 -0
- data/app/assets/javascripts/rollout_admin/application.js +19 -0
- data/app/assets/javascripts/rollout_admin/failures.js +2 -0
- data/app/assets/stylesheets/rollout_admin/admin.css +4 -0
- data/app/assets/stylesheets/rollout_admin/application.css +16 -0
- data/app/assets/stylesheets/rollout_admin/override.css.less +102 -0
- data/app/controllers/rollout_admin/admin_controller.rb +90 -0
- data/app/controllers/rollout_admin/application_controller.rb +4 -0
- data/app/helpers/rollout_admin/admin_helper.rb +4 -0
- data/app/helpers/rollout_admin/application_helper.rb +4 -0
- data/app/views/layouts/rollout_admin/application.html.erb +23 -0
- data/app/views/rollout_admin/admin/_feature.html.erb +71 -0
- data/app/views/rollout_admin/admin/_modals.html.erb +47 -0
- data/app/views/rollout_admin/admin/index.html.erb +26 -0
- data/config/routes.rb +12 -0
- data/lib/rollout_admin/engine.rb +5 -0
- data/lib/rollout_admin/version.rb +3 -0
- data/lib/rollout_admin.rb +4 -0
- data/lib/tasks/rollout_admin_tasks.rake +4 -0
- data/test/dummy/README.rdoc +261 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +15 -0
- data/test/dummy/app/assets/stylesheets/application.css +13 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/config/application.rb +59 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +37 -0
- data/test/dummy/config/environments/production.rb +67 -0
- data/test/dummy/config/environments/test.rb +37 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +15 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/rollout.rb +2 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +4 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/log/development.log +20262 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +25 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/dummy/tmp/cache/assets/C20/C40/sprockets%2F261100664832a5fd690af826f0851667 +0 -0
- data/test/dummy/tmp/cache/assets/C55/400/sprockets%2F9922ee592c403b460458680f1da79017 +0 -0
- data/test/dummy/tmp/cache/assets/C6D/6B0/sprockets%2F429143f762968712de61fb6c8629669e +0 -0
- data/test/dummy/tmp/cache/assets/C70/A20/sprockets%2F109d1361d6d5143160a288424a1b9ff3 +0 -0
- data/test/dummy/tmp/cache/assets/C78/460/sprockets%2F7d9501489510b06f2c36b455b1538e1b +0 -0
- data/test/dummy/tmp/cache/assets/C7F/680/sprockets%2F8d04822934a82a4e26599123a06fe17c +0 -0
- data/test/dummy/tmp/cache/assets/C8D/500/sprockets%2F2197959d63ad398e3abb7116574d7073 +0 -0
- data/test/dummy/tmp/cache/assets/C8E/370/sprockets%2F5715a23b738069dc623ff5d778259c70 +0 -0
- data/test/dummy/tmp/cache/assets/C96/930/sprockets%2F528e0632943be0f0d7c329f775a99688 +0 -0
- data/test/dummy/tmp/cache/assets/C9C/D90/sprockets%2F4a2d944b82b6411b4e3030cea0036896 +0 -0
- data/test/dummy/tmp/cache/assets/CA6/720/sprockets%2Fe54f120734cb3306547c49e23cd5c542 +0 -0
- data/test/dummy/tmp/cache/assets/CAB/130/sprockets%2Ff337a04f80ff3450c4103668a9064ad9 +0 -0
- data/test/dummy/tmp/cache/assets/CAE/F10/sprockets%2F16ff235a3919c04c0f0478414e59ca74 +0 -0
- data/test/dummy/tmp/cache/assets/CB3/100/sprockets%2F7187f0a20c6384eb48c29c70d008e388 +0 -0
- data/test/dummy/tmp/cache/assets/CB4/E00/sprockets%2F461896fc5136e1a54ca861480fb25f28 +0 -0
- data/test/dummy/tmp/cache/assets/CB5/DD0/sprockets%2Fc67208c4492b96c4332748c2c3e271ff +0 -0
- data/test/dummy/tmp/cache/assets/CB7/590/sprockets%2F764ce84c5b819b86fe552304ac814362 +0 -0
- data/test/dummy/tmp/cache/assets/CB9/6A0/sprockets%2Fd930e22f79e95b9b0331664d51666da6 +0 -0
- data/test/dummy/tmp/cache/assets/CBE/700/sprockets%2F00d72dab59c7e0a107102b8334b1e108 +0 -0
- data/test/dummy/tmp/cache/assets/CC1/1C0/sprockets%2Feb1b6997ba729596eb417627dc077345 +0 -0
- data/test/dummy/tmp/cache/assets/CC1/DA0/sprockets%2F675f039576d2fdc56653c7bc63d12875 +0 -0
- data/test/dummy/tmp/cache/assets/CC7/0C0/sprockets%2F7860733be5a69b995b7c9634530cf8e4 +0 -0
- data/test/dummy/tmp/cache/assets/CD2/3D0/sprockets%2F6fa3247d6904347a087bcb60ae4302f2 +0 -0
- data/test/dummy/tmp/cache/assets/CD2/B80/sprockets%2Ff31b41a931d6f0183c5cb0895483d21b +0 -0
- data/test/dummy/tmp/cache/assets/CD3/980/sprockets%2F03077d801d9c005f9a10f463f646c0fa +0 -0
- data/test/dummy/tmp/cache/assets/CD5/650/sprockets%2F3a67e7b7c24cb9f219112470c8f0304c +0 -0
- data/test/dummy/tmp/cache/assets/CD5/C00/sprockets%2F72b822081ea29032c5b7e7586bb5a22e +0 -0
- data/test/dummy/tmp/cache/assets/CD8/730/sprockets%2F32aabf38943204760722ca7e0c7fb288 +0 -0
- data/test/dummy/tmp/cache/assets/CDC/030/sprockets%2F5c09dc685263e63bdee05d5111a68525 +0 -0
- data/test/dummy/tmp/cache/assets/CDF/F20/sprockets%2Fb377780bb495f9308adc8f8c8040300a +0 -0
- data/test/dummy/tmp/cache/assets/CDF/FA0/sprockets%2Ff3348795f69c512ef32fce01d7006f00 +0 -0
- data/test/dummy/tmp/cache/assets/CEB/E40/sprockets%2Fdc0c77867a41f6512d992f5d380e429b +0 -0
- data/test/dummy/tmp/cache/assets/CEE/E80/sprockets%2F5a88f9906573e2187c61b4ce801e96ab +0 -0
- data/test/dummy/tmp/cache/assets/CF4/6A0/sprockets%2Fe14b6b684fe680f38f1166df49586b44 +0 -0
- data/test/dummy/tmp/cache/assets/CF8/220/sprockets%2F58cc7867e2797caf2081e9c8051c549f +0 -0
- data/test/dummy/tmp/cache/assets/D00/E70/sprockets%2F11823b27c41eed2102a188a853cbd8d7 +0 -0
- data/test/dummy/tmp/cache/assets/D04/190/sprockets%2F462b137adb8c4e37522d854b6a2eb730 +0 -0
- data/test/dummy/tmp/cache/assets/D06/ED0/sprockets%2F708d4ef91c962e6cb60012b0e2c53f25 +0 -0
- data/test/dummy/tmp/cache/assets/D0D/CA0/sprockets%2Fbb60dc938786ab2a91b28706cb32a298 +0 -0
- data/test/dummy/tmp/cache/assets/D0E/380/sprockets%2F4b12d7f74747f23c6017a4a7e965ab3c +0 -0
- data/test/dummy/tmp/cache/assets/D0E/760/sprockets%2Ffe56acc145c40e203265082f584e7d7e +0 -0
- data/test/dummy/tmp/cache/assets/D0E/ED0/sprockets%2F9261ee78b6d57ac5fe6171cb17114b61 +0 -0
- data/test/dummy/tmp/cache/assets/D10/C50/sprockets%2F6075c7bc4cc3b2d04d54bbc934709697 +0 -0
- data/test/dummy/tmp/cache/assets/D13/6F0/sprockets%2Fb12b479efabdb654778797e40044fa31 +0 -0
- data/test/dummy/tmp/cache/assets/D16/B20/sprockets%2F3e87067a172937368f3ddfdabcd14445 +0 -0
- data/test/dummy/tmp/cache/assets/D1F/440/sprockets%2Fd3862d1d68f97615f146311eab7d7f9d +0 -0
- data/test/dummy/tmp/cache/assets/D24/D00/sprockets%2F76e4073a159f5418f55ee35ca93f97ec +0 -0
- data/test/dummy/tmp/cache/assets/D28/0F0/sprockets%2Ff220f24f7de79602db8669ca8a18997f +0 -0
- data/test/dummy/tmp/cache/assets/D2C/D90/sprockets%2F3ec24ca7b474681701e355aa229bca3b +0 -0
- data/test/dummy/tmp/cache/assets/D32/1F0/sprockets%2Fe1af7c212b842ba6186afa058252c9f2 +0 -0
- data/test/dummy/tmp/cache/assets/D33/B80/sprockets%2F1c3371fbdb4f59fd006cb903018d257c +0 -0
- data/test/dummy/tmp/cache/assets/D3A/300/sprockets%2Ffaa86f001fde572c3be445509308c3b9 +0 -0
- data/test/dummy/tmp/cache/assets/D3E/340/sprockets%2Fc62625e05a6ab78fa7108bc91219ff6c +0 -0
- data/test/dummy/tmp/cache/assets/D42/130/sprockets%2F0ce4f38cdd901f2fb060876f217492df +0 -0
- data/test/dummy/tmp/cache/assets/D43/A00/sprockets%2F0af849366f9470e63fc22ec28ecc9a00 +0 -0
- data/test/dummy/tmp/cache/assets/D44/E80/sprockets%2F66ae491aae5c0e18e599d45e22e552b6 +0 -0
- data/test/dummy/tmp/cache/assets/D45/270/sprockets%2Fa9573efccd81ee042694caf103663e85 +0 -0
- data/test/dummy/tmp/cache/assets/D48/3F0/sprockets%2Fc73b9787cfd00e9ef343185e511fc3e3 +0 -0
- data/test/dummy/tmp/cache/assets/D4F/160/sprockets%2Fa05fd4653009b8a45acb40f0ad2d412b +0 -0
- data/test/dummy/tmp/cache/assets/D4F/B50/sprockets%2F70467bdfb28b8966960e3d0c589e2add +0 -0
- data/test/dummy/tmp/cache/assets/D55/3C0/sprockets%2F5a0966ba1bff69a36fe2f39473f9b399 +0 -0
- data/test/dummy/tmp/cache/assets/D6B/250/sprockets%2Fedf4f5f302a722e3fd6f6509b3ed1810 +0 -0
- data/test/dummy/tmp/cache/assets/D6B/B30/sprockets%2Fb7cf44c5e1ea68800d9e3a9235ae5a60 +0 -0
- data/test/dummy/tmp/cache/assets/D6C/0C0/sprockets%2F1ac2e63a2b7fd76b515eb5d95b2856a5 +0 -0
- data/test/dummy/tmp/cache/assets/D6C/B30/sprockets%2F1d5ec72e04cd10fb8c90bbda87088817 +0 -0
- data/test/dummy/tmp/cache/assets/D6D/870/sprockets%2Fee06e0b902601c67d24c9fb7a3cbe696 +0 -0
- data/test/dummy/tmp/cache/assets/D71/C20/sprockets%2Fc7303b23dce837fa7b76f4125fc4e46e +0 -0
- data/test/dummy/tmp/cache/assets/D71/FF0/sprockets%2Fc57f0246fc0b8ee64dc164f34a52c6d9 +0 -0
- data/test/dummy/tmp/cache/assets/D72/7C0/sprockets%2Fef5c15a386af59791adc70444adc93d2 +0 -0
- data/test/dummy/tmp/cache/assets/D74/A80/sprockets%2F18ba650d0ac50053fe8cf97f9db98f31 +0 -0
- data/test/dummy/tmp/cache/assets/D7A/530/sprockets%2Fa45e2fe38b2980a24c715997edfbb3e7 +0 -0
- data/test/dummy/tmp/cache/assets/D83/AC0/sprockets%2F784c9ffae2dd6a84e91293a8b078cd83 +0 -0
- data/test/dummy/tmp/cache/assets/D90/660/sprockets%2F1cc7ddd5f049da1ab735a137e7424b3c +0 -0
- data/test/dummy/tmp/cache/assets/D97/3F0/sprockets%2F73b6a9e91e1c3dfbde7df506063f030a +0 -0
- data/test/dummy/tmp/cache/assets/D9A/F70/sprockets%2F9b3298a5ca38cbfb3fb9a062ee36b180 +0 -0
- data/test/dummy/tmp/cache/assets/DA1/B70/sprockets%2F6fd2228ab269ca977b97aab086c60fda +0 -0
- data/test/dummy/tmp/cache/assets/DA2/090/sprockets%2F472d4241ad9f4b6e791f5f8dfd31ce0a +0 -0
- data/test/dummy/tmp/cache/assets/DA2/BB0/sprockets%2F20dc7d35189b5b8b2de1d4d072e9ff7c +0 -0
- data/test/dummy/tmp/cache/assets/DA6/C70/sprockets%2F78df72bc3eb5d94abf5f652cb20708e7 +0 -0
- data/test/dummy/tmp/cache/assets/DA6/F90/sprockets%2Fe75e1ebb6089a1862bfdb14588f8d3ac +0 -0
- data/test/dummy/tmp/cache/assets/DAA/420/sprockets%2Ff4b2a98efc26e6289263cc0d3bd79c4e +0 -0
- data/test/dummy/tmp/cache/assets/DAC/F50/sprockets%2Faf5a558648cd7bc81e5b85df6fa125d7 +0 -0
- data/test/dummy/tmp/cache/assets/DB2/0A0/sprockets%2Faeac771697881809329b2ebeeced8bf6 +0 -0
- data/test/dummy/tmp/cache/assets/DBD/330/sprockets%2F51a9cf8afaaa9b816cb8a70ac7512a21 +0 -0
- data/test/dummy/tmp/cache/assets/DBF/B40/sprockets%2Fe00c05fe811a5201ecf81e1af8e6eca8 +0 -0
- data/test/dummy/tmp/cache/assets/DC1/AB0/sprockets%2F2e20ea6c418db23cb9c2cf1782a95cad +0 -0
- data/test/dummy/tmp/cache/assets/DCB/240/sprockets%2F23b7eecc9a7c0c38f7c5316efaa60e17 +0 -0
- data/test/dummy/tmp/cache/assets/DD2/1E0/sprockets%2F9ead9f72b0d11cb7a9f5637f77ab13be +0 -0
- data/test/dummy/tmp/cache/assets/DD9/300/sprockets%2Fa24d5e2b2b38e7faf91cf3738d6f48ec +0 -0
- data/test/dummy/tmp/cache/assets/DDB/AA0/sprockets%2Ff9b53bed9958305cff6ff8dc0f330bd2 +0 -0
- data/test/dummy/tmp/cache/assets/DDC/990/sprockets%2F4a1cef3fbac3d74d9a15d3997ed9918c +0 -0
- data/test/dummy/tmp/cache/assets/DDD/E70/sprockets%2F0b0e2c06badeabd4ea9b52178b44a00e +0 -0
- data/test/dummy/tmp/cache/assets/DEF/610/sprockets%2Fe23e6b6dadeb8f01ab452bab578a532e +0 -0
- data/test/dummy/tmp/cache/assets/DF0/D30/sprockets%2F88ab3631daac054acf95528ce1acc4cd +0 -0
- data/test/dummy/tmp/cache/assets/DF4/4C0/sprockets%2Fa722b8a28bce4d3346bd0be5f46bdae7 +0 -0
- data/test/dummy/tmp/cache/assets/DFB/360/sprockets%2Fbe14b4380ce7db7ec289dbe3d4cfa092 +0 -0
- data/test/dummy/tmp/cache/assets/DFB/570/sprockets%2F15ee84ca369789a1c4adf2cc0a2ffea4 +0 -0
- data/test/dummy/tmp/cache/assets/DFC/E40/sprockets%2F8fde3a1113aeecd77fb2f27c0e276be8 +0 -0
- data/test/dummy/tmp/cache/assets/E0B/DF0/sprockets%2Fd1a8c47b74aa53edbb5288992ddedd9f +0 -0
- data/test/dummy/tmp/cache/assets/E33/010/sprockets%2Ffd7db48da51f060c6bdd80dfbd992d8b +0 -0
- data/test/dummy/tmp/cache/assets/E33/050/sprockets%2Fe5ce222fae640d1bf9f3fc96eaa87fb4 +0 -0
- data/test/dummy/tmp/cache/assets/E3D/4A0/sprockets%2F6954eff7c65c4d1fc8d8571aeecaafd3 +0 -0
- data/test/dummy/tmp/cache/assets/EBF/FA0/sprockets%2Fafa901c76afcff908decda3eea27b9be +0 -0
- data/test/functional/rollout_admin/admin_controller_test.rb +11 -0
- data/test/integration/navigation_test.rb +10 -0
- data/test/rollout_admin_test.rb +7 -0
- data/test/test_helper.rb +15 -0
- data/test/unit/helpers/rollout_admin/admin_helper_test.rb +6 -0
- metadata +444 -0
data/MIT-LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright 2013 Alexander Balsam
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
= RolloutAdmin
|
|
2
|
+
|
|
3
|
+
Gem to controll your rollout features via a webinterface. This is the first "not yet clean" version. Please do not use in production environment.
|
|
4
|
+
|
|
5
|
+
== INSTALL
|
|
6
|
+
|
|
7
|
+
Add rollout_admin to your Gemfile. Then bundle install. Make sure you have rollout installed as well from nedeco git because rollout_admin relies on the IP address extension.
|
|
8
|
+
|
|
9
|
+
rollout_admin expects that you have a User model with the attributes "id", "name", "email". Rollout must be initialized and available viw $rollout variable.
|
|
10
|
+
|
|
11
|
+
Add the following line to your routes.rb:
|
|
12
|
+
|
|
13
|
+
mount RolloutAdmin::Engine => "/rollout_admin"
|
|
14
|
+
|
|
15
|
+
You will be asked for a username and password. This is "foo/bar".
|
|
16
|
+
|
|
17
|
+
== TODO
|
|
18
|
+
|
|
19
|
+
- check dependencies
|
|
20
|
+
- make detailed install instructions
|
|
21
|
+
- add configuration for authentication
|
|
22
|
+
- make ip feature configurable
|
|
23
|
+
- make User model dependency more generic
|
data/Rakefile
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env rake
|
|
2
|
+
begin
|
|
3
|
+
require 'bundler/setup'
|
|
4
|
+
rescue LoadError
|
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
|
6
|
+
end
|
|
7
|
+
begin
|
|
8
|
+
require 'rdoc/task'
|
|
9
|
+
rescue LoadError
|
|
10
|
+
require 'rdoc/rdoc'
|
|
11
|
+
require 'rake/rdoctask'
|
|
12
|
+
RDoc::Task = Rake::RDocTask
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
17
|
+
rdoc.title = 'RolloutAdmin'
|
|
18
|
+
rdoc.options << '--line-numbers'
|
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
|
|
24
|
+
load 'rails/tasks/engine.rake'
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
Bundler::GemHelper.install_tasks
|
|
29
|
+
|
|
30
|
+
require 'rake/testtask'
|
|
31
|
+
|
|
32
|
+
Rake::TestTask.new(:test) do |t|
|
|
33
|
+
t.libs << 'lib'
|
|
34
|
+
t.libs << 'test'
|
|
35
|
+
t.pattern = 'test/**/*_test.rb'
|
|
36
|
+
t.verbose = false
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
task :default => :test
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
<%
|
|
2
|
+
# import the routes from the engine router to be aware
|
|
3
|
+
# of the mount path when doing javascript ajax calls
|
|
4
|
+
url = RolloutAdmin::Engine.routes.url_helpers
|
|
5
|
+
%>
|
|
6
|
+
|
|
7
|
+
$(function(){
|
|
8
|
+
$('a.icon-chevron-down').click(
|
|
9
|
+
function(){
|
|
10
|
+
$(this).parent().find('div.details').fadeIn(1000);
|
|
11
|
+
$(this).hide();
|
|
12
|
+
$(this).parent().find('a.icon-chevron-up').show();
|
|
13
|
+
}
|
|
14
|
+
);
|
|
15
|
+
$('a.icon-chevron-up').click(
|
|
16
|
+
function(){
|
|
17
|
+
$(this).parent().find('div.details').fadeOut(500);
|
|
18
|
+
$(this).hide();
|
|
19
|
+
$(this).parent().find('a.icon-chevron-down').show();
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
$(document).delegate('i.delete_user', 'click',
|
|
24
|
+
function(){
|
|
25
|
+
var context=$(this).closest("div").parent().find("h4#feature_name").html(),
|
|
26
|
+
that=$(this).closest("li"),
|
|
27
|
+
ulist=$(this).closest("ul");
|
|
28
|
+
$.post('<%= url.remove_path(:format => :json )%>', {object_type:"user", user: $(this).closest("li").text(), feature: context}, function(data) {
|
|
29
|
+
that.remove();
|
|
30
|
+
if ($("li",ulist).length == 1) {
|
|
31
|
+
ulist.children(':last').before('<li>No members</li>');
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
$(document).delegate('i.delete_group','click',
|
|
37
|
+
function(){
|
|
38
|
+
var context=$(this).closest("div").parent().find("h4#feature_name").html(),
|
|
39
|
+
that=$(this).closest("li"),
|
|
40
|
+
ulist=$(this).closest("ul");
|
|
41
|
+
$.post('<%= url.remove_path(:format => :json )%>', {object_type:"group", group: $(this).closest("li").text(), feature: context}, function(data) {
|
|
42
|
+
that.remove();
|
|
43
|
+
if ($("li",ulist).length == 1) {
|
|
44
|
+
ulist.children(':last').before('<li>No members</li>');
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
$(document).delegate('i.delete_ip','click',
|
|
50
|
+
function(){
|
|
51
|
+
var context=$(this).closest("div").parent().find("h4#feature_name").html(),
|
|
52
|
+
that=$(this).closest("li"),
|
|
53
|
+
ulist=$(this).closest("ul");
|
|
54
|
+
$.post('<%= url.remove_path(:format => :json )%>', {object_type:"ip", ip: $(this).closest("li").text(), feature: context}, function(data) {
|
|
55
|
+
that.remove();
|
|
56
|
+
if ($("li",ulist).length == 1) {
|
|
57
|
+
ulist.children(':last').before('<li>No members</li>');
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
$('i.add_users').click(
|
|
64
|
+
function(){
|
|
65
|
+
context=$(this).closest("div").parent().find("h4#feature_name").html();
|
|
66
|
+
$('.feature_name').html(context);
|
|
67
|
+
$that = $(this);
|
|
68
|
+
|
|
69
|
+
$.getJSON('<%= url.get_users_path(:format => :json )%>', function(json) {
|
|
70
|
+
userlist='<h5>Select users to add</h5><form id="userlist"><ul class="unstyled">';
|
|
71
|
+
$.each(json, function() {
|
|
72
|
+
userlist += '<li><input type="checkbox", value="'+this.id+'" data-username="'+this.Name+'"> '+this.Name+', '+this.email+'</li>';
|
|
73
|
+
});
|
|
74
|
+
userlist +='</ul></form>';
|
|
75
|
+
|
|
76
|
+
$('#addUserModal').find("div.modal-body").html(userlist);
|
|
77
|
+
|
|
78
|
+
// clear former event handlers
|
|
79
|
+
$('#addUserModal').find("div.modal-footer").find("button.btn-primary").unbind();
|
|
80
|
+
$('#addUserModal').find("div.modal-footer").find("button.btn-primary").click(function() {
|
|
81
|
+
var allUsers = [];
|
|
82
|
+
var allUserNames = [];
|
|
83
|
+
$('#userlist :checked').each(function() {
|
|
84
|
+
allUsers.push($(this).val());
|
|
85
|
+
allUserNames.push($(this).data("username"));
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
$.post('<%= url.add_path(:format => :json )%>', {object_type:"user", user: allUsers.join(), feature: context}, function(data) {
|
|
89
|
+
list = $that.closest('ul');
|
|
90
|
+
if (list.children(':first').text() == "No members") {
|
|
91
|
+
list.children(':first').remove();
|
|
92
|
+
}
|
|
93
|
+
allUserNames.forEach(function(entry) {
|
|
94
|
+
list.children(':last').before('<li><i class="icon-minus delete_user"></i>'+entry+'</li>');
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
$('#addUserModal').modal('hide');
|
|
98
|
+
});
|
|
99
|
+
$('#addUserModal').modal();
|
|
100
|
+
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
}
|
|
104
|
+
);
|
|
105
|
+
$('i.add_groups').click(
|
|
106
|
+
function(){
|
|
107
|
+
context=$(this).closest("div").parent().find("h4#feature_name").html();
|
|
108
|
+
$('.feature_name').html(context);
|
|
109
|
+
$that = $(this);
|
|
110
|
+
|
|
111
|
+
// clear former event handlers
|
|
112
|
+
$('#addGroupModal').find("div.modal-footer").find("button.btn-primary").unbind();
|
|
113
|
+
$('#addGroupModal').find("div.modal-footer").find("button.btn-primary").click(function() {
|
|
114
|
+
$.post('<%= url.add_path(:format => :json )%>', {object_type:"group", group: $('#addGroupModal').find("div.modal-body").find("input#group_name").val(), feature: context}, function(data) {
|
|
115
|
+
list = $that.closest('ul');
|
|
116
|
+
if (list.children(':first').text() == "No members") {
|
|
117
|
+
list.children(':first').remove();
|
|
118
|
+
}
|
|
119
|
+
list.children(':last').before('<li><i class="icon-minus delete_group"></i>'+$('#addGroupModal').find("div.modal-body").find("input#group_name").val()+'</li>');
|
|
120
|
+
$('#addGroupModal').find("div.modal-body").find("input#group_name").val('');
|
|
121
|
+
});
|
|
122
|
+
$('#addGroupModal').modal('hide');
|
|
123
|
+
});
|
|
124
|
+
$('#addGroupModal').modal();
|
|
125
|
+
}
|
|
126
|
+
);
|
|
127
|
+
$('i.add_ips').click(
|
|
128
|
+
function(){
|
|
129
|
+
context=$(this).closest("div").parent().find("h4#feature_name").html();
|
|
130
|
+
$('.feature_name').html(context);
|
|
131
|
+
$that = $(this);
|
|
132
|
+
|
|
133
|
+
// clear former event handlers
|
|
134
|
+
$('#addIPModal').find("div.modal-footer").find("button.btn-primary").unbind();
|
|
135
|
+
$('#addIPModal').find("div.modal-footer").find("button.btn-primary").click(function() {
|
|
136
|
+
$.post('<%= url.add_path(:format => :json )%>', {object_type:"ip", ip: $('#addIPModal').find("div.modal-body").find("input#ipaddr").val(), feature: context}, function(data) {
|
|
137
|
+
|
|
138
|
+
list = $that.closest('ul');
|
|
139
|
+
if (list.children(':first').text() == "No members") {
|
|
140
|
+
list.children(':first').remove();
|
|
141
|
+
}
|
|
142
|
+
list.children(':last').before('<li><i class="icon-minus delete_ip"></i>'+$('#addIPModal').find("div.modal-body").find("input#ipaddr").val()+'</li>');
|
|
143
|
+
$('#addIPModal').find("div.modal-body").find("input#ipaddr").val('');
|
|
144
|
+
});
|
|
145
|
+
$('#addIPModal').modal('hide');
|
|
146
|
+
});
|
|
147
|
+
$('#addIPModal').modal();
|
|
148
|
+
}
|
|
149
|
+
);
|
|
150
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
|
2
|
+
// listed below.
|
|
3
|
+
//
|
|
4
|
+
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
|
5
|
+
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
|
|
6
|
+
//
|
|
7
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
|
8
|
+
// the compiled file.
|
|
9
|
+
//
|
|
10
|
+
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
|
|
11
|
+
// GO AFTER THE REQUIRES BELOW.
|
|
12
|
+
//
|
|
13
|
+
//= require jquery
|
|
14
|
+
//= require jquery_ujs
|
|
15
|
+
//= require jquery.ui.slider
|
|
16
|
+
//= require jquery.ui.dialog
|
|
17
|
+
//= require jquery.ui.datepicker
|
|
18
|
+
//= require twitter/bootstrap
|
|
19
|
+
//= require_tree .
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
|
3
|
+
* listed below.
|
|
4
|
+
*
|
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
|
6
|
+
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
|
|
7
|
+
*
|
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the top of the
|
|
9
|
+
* compiled file, but it's generally better to create a new file per style scope.
|
|
10
|
+
*
|
|
11
|
+
*= require twitter/bootstrap
|
|
12
|
+
*= require_self
|
|
13
|
+
*= require jquery.ui.slider
|
|
14
|
+
*= require jquery.ui.datepicker
|
|
15
|
+
*= require_tree .
|
|
16
|
+
*/
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
|
|
2
|
+
@import "twitter/bootstrap/variables";
|
|
3
|
+
@import "twitter/bootstrap/mixins";
|
|
4
|
+
@import "twitter/bootstrap/responsive";
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
/* clearfix */
|
|
8
|
+
.cf{
|
|
9
|
+
zoom:1;
|
|
10
|
+
&:before,
|
|
11
|
+
&:after{
|
|
12
|
+
content:"";
|
|
13
|
+
display:table;
|
|
14
|
+
}
|
|
15
|
+
&:after{
|
|
16
|
+
clear:both;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
html, body {
|
|
21
|
+
background: url(/assets/rollout_admin/main_bg.jpg);
|
|
22
|
+
font-family: 'Roboto Condensed', sans-serif;
|
|
23
|
+
font-size: 12px;
|
|
24
|
+
color: @white;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
header {
|
|
28
|
+
z-index: 100;
|
|
29
|
+
position: fixed;
|
|
30
|
+
display: block;
|
|
31
|
+
height: 60px;
|
|
32
|
+
box-shadow: 0 0 30px @darkblue;
|
|
33
|
+
background: url(/assets/rollout_admin/head_bg.jpg);
|
|
34
|
+
border-bottom: 5px solid @blue;
|
|
35
|
+
width: 100%;
|
|
36
|
+
|
|
37
|
+
@media (max-width: 767px) {
|
|
38
|
+
margin-left: -20px;
|
|
39
|
+
margin-right: -20px;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.app_icon {
|
|
43
|
+
margin: 6px;
|
|
44
|
+
cursor: pointer;
|
|
45
|
+
}
|
|
46
|
+
a.addlist i {
|
|
47
|
+
margin: 18px 10px;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.title {
|
|
52
|
+
color: #fff;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
div.container{
|
|
56
|
+
padding-top: 70px;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
.transition (@time: 0.2s) {
|
|
61
|
+
transition: all @time;
|
|
62
|
+
-moz-transition: all @time; /* Firefox 4 */
|
|
63
|
+
-webkit-transition: all @time; /* Safari and Chrome */
|
|
64
|
+
-o-transition: all @time; /* Opera */
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.corners (@radius: 5px) {
|
|
68
|
+
-webkit-border-radius: @radius;
|
|
69
|
+
-moz-border-radius: @radius;
|
|
70
|
+
-ms-border-radius: @radius;
|
|
71
|
+
-o-border-radius: @radius;
|
|
72
|
+
border-radius: @radius;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
@darkblue: #04263a;
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
div.feature {
|
|
80
|
+
color: #111;
|
|
81
|
+
background-color: #eee;
|
|
82
|
+
margin-bottom: 20px;
|
|
83
|
+
box-shadow: 0 5px 20px #000;
|
|
84
|
+
|
|
85
|
+
padding: 10px;
|
|
86
|
+
border: solid 1px #ccc;
|
|
87
|
+
.box-sizing(border-box);
|
|
88
|
+
.border-radius( 5px );
|
|
89
|
+
.actions {
|
|
90
|
+
position:relative;
|
|
91
|
+
bottom: 25px;
|
|
92
|
+
float: right;
|
|
93
|
+
}
|
|
94
|
+
.details {
|
|
95
|
+
display:none;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
div.modal {
|
|
100
|
+
color: #111;
|
|
101
|
+
}
|
|
102
|
+
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
require_dependency "rollout_admin/application_controller"
|
|
2
|
+
|
|
3
|
+
module RolloutAdmin
|
|
4
|
+
class AdminController < ApplicationController
|
|
5
|
+
|
|
6
|
+
before_filter :authenticate
|
|
7
|
+
|
|
8
|
+
def index
|
|
9
|
+
@feature_list = $rollout.features
|
|
10
|
+
@features = []
|
|
11
|
+
@feature_list.uniq.each { |feature|
|
|
12
|
+
@features << $rollout.get(feature)
|
|
13
|
+
}
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def create
|
|
17
|
+
$rollout.activate_percentage(params[:feature_name], 0)
|
|
18
|
+
redirect_to index_path
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def deactivate
|
|
22
|
+
if params[:object_type] == "feature"
|
|
23
|
+
$rollout.deactivate(params[:object].to_s)
|
|
24
|
+
end
|
|
25
|
+
redirect_to index_path
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def activate
|
|
29
|
+
if params[:object_type] == "feature"
|
|
30
|
+
$rollout.activate(params[:object].to_s)
|
|
31
|
+
end
|
|
32
|
+
redirect_to index_path
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def get_users
|
|
36
|
+
@users=User.all
|
|
37
|
+
render :json => @users
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def add
|
|
41
|
+
if params[:object_type] == "user"
|
|
42
|
+
$rollout.activate_user(params[:feature], User.find(params[:user].to_i))
|
|
43
|
+
@feature = $rollout.get(params[:feature])
|
|
44
|
+
render :json => @feature.users
|
|
45
|
+
elsif params[:object_type] == "group"
|
|
46
|
+
$rollout.activate_group(params[:feature], params[:group].to_sym)
|
|
47
|
+
@feature = $rollout.get(params[:feature])
|
|
48
|
+
render :json => @feature.groups
|
|
49
|
+
elsif params[:object_type] == "ip"
|
|
50
|
+
$rollout.activate_ip(params[:feature], params[:ip].to_s)
|
|
51
|
+
@feature = $rollout.get(params[:feature])
|
|
52
|
+
render :json => @feature.ips
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def remove
|
|
57
|
+
if params[:object_type] == "user"
|
|
58
|
+
@user=User.where(:name => params[:user]).first
|
|
59
|
+
if @user
|
|
60
|
+
$rollout.deactivate_user(params[:feature], @user)
|
|
61
|
+
end
|
|
62
|
+
@feature = $rollout.get(params[:feature])
|
|
63
|
+
render :json => @feature.users
|
|
64
|
+
elsif params[:object_type] == "group"
|
|
65
|
+
$rollout.deactivate_group(params[:feature], params[:group].to_sym)
|
|
66
|
+
@feature = $rollout.get(params[:feature])
|
|
67
|
+
render :json => @feature.groups
|
|
68
|
+
elsif params[:object_type] == "ip"
|
|
69
|
+
puts params[:ip]
|
|
70
|
+
$rollout.deactivate_ip(params[:feature], params[:ip].to_s)
|
|
71
|
+
@feature = $rollout.get(params[:feature])
|
|
72
|
+
render :json => @feature.ips
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def update_percentage
|
|
77
|
+
$rollout.activate_percentage(params[:feature].to_sym,params[:percentage].to_i)
|
|
78
|
+
render :json => {:status => "success"}
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
protected
|
|
82
|
+
|
|
83
|
+
def authenticate
|
|
84
|
+
authenticate_or_request_with_http_basic do |username, password|
|
|
85
|
+
username == "foo" && password == "bar"
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<title>RolloutAdmin</title>
|
|
5
|
+
<%= stylesheet_link_tag "rollout_admin/application", :media => "all" %>
|
|
6
|
+
<%= javascript_include_tag "rollout_admin/application" %>
|
|
7
|
+
<link href='http://fonts.googleapis.com/css?family=Roboto+Condensed' rel='stylesheet' type='text/css'>
|
|
8
|
+
|
|
9
|
+
<%= csrf_meta_tags %>
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<header>
|
|
13
|
+
<div class="dropdown" style="float:left;">
|
|
14
|
+
<%= image_tag "rollout_admin/icon_todos50x50.png", :class => "app_icon", :style => "float:left; margin-right: 20px;" %>
|
|
15
|
+
<h1 style="float:left;">Feature Administration</h1>
|
|
16
|
+
</div>
|
|
17
|
+
</header>
|
|
18
|
+
|
|
19
|
+
<div class="container">
|
|
20
|
+
<%= yield %>
|
|
21
|
+
</div>
|
|
22
|
+
</body>
|
|
23
|
+
</html>
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<div class="feature">
|
|
2
|
+
<h4 id="feature_name"><%=feature.name%></h4>
|
|
3
|
+
<a class="icon-chevron-down"></a>
|
|
4
|
+
<a class="icon-chevron-up" style="display:none;"></a>
|
|
5
|
+
<%#=$rollout.get(feature).inspect%>
|
|
6
|
+
<div id="details" class="details">
|
|
7
|
+
<dl class="dl-horizontal">
|
|
8
|
+
<dt>Users</dt>
|
|
9
|
+
<dd>
|
|
10
|
+
<ul class="unstyled">
|
|
11
|
+
<% if feature.users.count > 0 %>
|
|
12
|
+
<% feature.users.each {|user| %>
|
|
13
|
+
<li><i class="icon-minus delete_user"></i><%=User.find(user.to_i).Name%></li>
|
|
14
|
+
<% } %>
|
|
15
|
+
<% else %>
|
|
16
|
+
<li>No members</li>
|
|
17
|
+
<% end %>
|
|
18
|
+
<li><i class="icon-plus add_users"></i></li>
|
|
19
|
+
</ul>
|
|
20
|
+
</dd>
|
|
21
|
+
<dt>Groups</dt>
|
|
22
|
+
<dd>
|
|
23
|
+
<ul class="unstyled">
|
|
24
|
+
<% if feature.groups.count > 0 %>
|
|
25
|
+
<% feature.groups.each {|group| %>
|
|
26
|
+
<li><i class="icon-minus delete_group"></i><%=group%></li>
|
|
27
|
+
<% } %>
|
|
28
|
+
<% else %>
|
|
29
|
+
<li>No members</li>
|
|
30
|
+
<% end %>
|
|
31
|
+
<li><i class="icon-plus add_groups"></i></li>
|
|
32
|
+
</ul>
|
|
33
|
+
</dd>
|
|
34
|
+
<dt>IPs</dt>
|
|
35
|
+
<dd>
|
|
36
|
+
<ul class="unstyled">
|
|
37
|
+
<% if feature.ips.count > 0 %>
|
|
38
|
+
<% feature.ips.each {|ip| %>
|
|
39
|
+
<li><i class="icon-minus delete_ip"></i><%=ip%></li>
|
|
40
|
+
<% } %>
|
|
41
|
+
<% else %>
|
|
42
|
+
<li>No members</li>
|
|
43
|
+
<% end %>
|
|
44
|
+
<li><i class="icon-plus add_ips"></i></li>
|
|
45
|
+
</ul>
|
|
46
|
+
</dd>
|
|
47
|
+
<dt>Percentage</dt>
|
|
48
|
+
<dd>
|
|
49
|
+
<div id="slider_<%=feature.name%>" style="width: 100%;"></div>
|
|
50
|
+
<p class="slider-input" style="width: 100%; text-align:center;"><%=feature.percentage%>%</p>
|
|
51
|
+
</dd>
|
|
52
|
+
</dl>
|
|
53
|
+
</div>
|
|
54
|
+
<div class="btn-group actions">
|
|
55
|
+
<%= link_to "activate global", "/rollout_admin/activate?object_type=feature&object="+ feature.name.to_s, :method => :post, :class => "btn"%>
|
|
56
|
+
|
|
57
|
+
<%= link_to "deactivate global", "/rollout_admin/deactivate?object_type=feature&object="+ feature.name.to_s, :method => :post, :class => "btn"%>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
<script>
|
|
61
|
+
$("#slider_<%=feature.name%>").slider({
|
|
62
|
+
value: <%=feature.percentage%>,
|
|
63
|
+
'slide': function(e, ui){
|
|
64
|
+
console.log($(this).siblings('.slider-input'));
|
|
65
|
+
$(this).siblings('.slider-input').html(ui.value + "%");
|
|
66
|
+
$.post('<%= update_percentage_path(:format => :json )%>', {percentage: ui.value, feature: "<%=feature.name%>"}, function(data) {
|
|
67
|
+
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
</script>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<!-- addUserModal-->
|
|
2
|
+
<div id="addUserModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
|
3
|
+
<div class="modal-header">
|
|
4
|
+
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
|
5
|
+
<h3 id="myModalLabel">Add User to <p class="feature_name"></p></h3>
|
|
6
|
+
</div>
|
|
7
|
+
<div class="modal-body">
|
|
8
|
+
<p>here we will display all users</p>
|
|
9
|
+
</div>
|
|
10
|
+
<div class="modal-footer">
|
|
11
|
+
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
|
|
12
|
+
<button class="btn btn-primary">Save changes</button>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
<!-- addGroupModal-->
|
|
17
|
+
<div id="addGroupModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
|
18
|
+
<div class="modal-header">
|
|
19
|
+
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
|
20
|
+
<h3 id="myModalLabel">Add Group to <p class="feature_name"></p></h3>
|
|
21
|
+
</div>
|
|
22
|
+
<div class="modal-body">
|
|
23
|
+
<p>Group name</p>
|
|
24
|
+
<input type="text" name="group_name" id="group_name">
|
|
25
|
+
<p>Please type in the name of a group you would like to add.</p>
|
|
26
|
+
</div>
|
|
27
|
+
<div class="modal-footer">
|
|
28
|
+
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
|
|
29
|
+
<button class="btn btn-primary">Save changes</button>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<!-- addIPModal-->
|
|
34
|
+
<div id="addIPModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
|
35
|
+
<div class="modal-header">
|
|
36
|
+
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
|
37
|
+
<h3 id="myModalLabel">Add IP to <p class="feature_name"></p></h3>
|
|
38
|
+
</div>
|
|
39
|
+
<div class="modal-body">
|
|
40
|
+
<p>IP address</p>
|
|
41
|
+
<input type="text" name="ipaddr" id="ipaddr">
|
|
42
|
+
<p>Please type in the ip address you would like to add.</p> </div>
|
|
43
|
+
<div class="modal-footer">
|
|
44
|
+
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
|
|
45
|
+
<button class="btn btn-primary">Save changes</button>
|
|
46
|
+
</div>
|
|
47
|
+
</div>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<div class="row">
|
|
2
|
+
<div class="span12">
|
|
3
|
+
<div class="page-header">
|
|
4
|
+
<h1><small>available features</small></h1>
|
|
5
|
+
</div>
|
|
6
|
+
<div class="row">
|
|
7
|
+
<div class="span8">
|
|
8
|
+
<% @features.each { |f| %>
|
|
9
|
+
<%= render :partial => "feature", :object => f%>
|
|
10
|
+
<% } %>
|
|
11
|
+
</div>
|
|
12
|
+
<div class="span4">
|
|
13
|
+
<h4>Add another features</h4>
|
|
14
|
+
<%= form_tag(create_path, :method => "post") do %>
|
|
15
|
+
<%= label_tag(:feature_name, "Feature name") %>
|
|
16
|
+
<%= text_field_tag(:feature_name) %>
|
|
17
|
+
<%= submit_tag("Create") %>
|
|
18
|
+
<p><br /><b>Attention</b><br />
|
|
19
|
+
Adding a feature only means that you defined a feature within the your redis database. You have to write the code yourself that enables the functionality.
|
|
20
|
+
</p>
|
|
21
|
+
<% end %>
|
|
22
|
+
</div>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
<%= render :partial => "modals"%>
|