chef-server-api 0.8.2
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/LICENSE +201 -0
- data/README.rdoc +92 -0
- data/Rakefile +59 -0
- data/app/controllers/application.rb +289 -0
- data/app/controllers/clients.rb +111 -0
- data/app/controllers/cookbooks.rb +213 -0
- data/app/controllers/data.rb +75 -0
- data/app/controllers/data_item.rb +108 -0
- data/app/controllers/exceptions.rb +40 -0
- data/app/controllers/main.rb +18 -0
- data/app/controllers/nodes.rb +102 -0
- data/app/controllers/roles.rb +73 -0
- data/app/controllers/search.rb +60 -0
- data/app/controllers/users.rb +77 -0
- data/app/helpers/application_helper.rb +163 -0
- data/app/helpers/exceptions_helper.rb +6 -0
- data/app/helpers/global_helpers.rb +25 -0
- data/app/helpers/nodes_helper.rb +26 -0
- data/app/helpers/roles_helper.rb +5 -0
- data/app/helpers/tarball_helper.rb +82 -0
- data/app/views/exceptions/bad_request.json.erb +1 -0
- data/app/views/exceptions/internal_server_error.html.erb +216 -0
- data/app/views/exceptions/not_acceptable.html.haml +5 -0
- data/app/views/exceptions/not_found.html.erb +47 -0
- data/app/views/exceptions/standard_error.html.erb +217 -0
- data/app/views/layout/chef_server_api.html.haml +23 -0
- data/app/views/main/index.html.haml +5 -0
- data/config/init.rb +45 -0
- data/config/router.rb +6 -0
- data/lib/chef-server-api.rb +158 -0
- data/lib/chef-server-api/merbtasks.rb +103 -0
- data/lib/chef-server-api/slicetasks.rb +20 -0
- data/lib/chef-server-api/spectasks.rb +53 -0
- data/public/images/avatar.png +0 -0
- data/public/images/indicator.gif +0 -0
- data/public/images/merb.jpg +0 -0
- data/public/stylesheets/base.css +336 -0
- data/public/stylesheets/chef.css +157 -0
- data/public/stylesheets/themes/bec-green/style.css +290 -0
- data/public/stylesheets/themes/bec/style.css +301 -0
- data/public/stylesheets/themes/blue/style.css +280 -0
- data/public/stylesheets/themes/default/style.css +267 -0
- data/public/stylesheets/themes/djime-cerulean/style.css +298 -0
- data/public/stylesheets/themes/kathleene/style.css +272 -0
- data/public/stylesheets/themes/orange/style.css +263 -0
- data/public/stylesheets/themes/reidb-greenish/style.css +301 -0
- data/stubs/app/controllers/application.rb +2 -0
- data/stubs/app/controllers/main.rb +2 -0
- metadata +193 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
!!! XML
|
2
|
+
!!!
|
3
|
+
%html
|
4
|
+
%head
|
5
|
+
%meta{ "http-equiv" => "content-type", :content => "text/html; charset=utf-8" }
|
6
|
+
%title Chef Server
|
7
|
+
= css_include_tag "base", "themes/djime-cerulean/style", "chef"
|
8
|
+
%body
|
9
|
+
#container
|
10
|
+
#header
|
11
|
+
%h1= link_to "Chef REST API", absolute_slice_url(:top)
|
12
|
+
#main-navigation
|
13
|
+
.clear
|
14
|
+
#wrapper
|
15
|
+
#main
|
16
|
+
= catch_content :for_layout
|
17
|
+
#footer
|
18
|
+
.block
|
19
|
+
%p Copyright © 2009 Opscode, Inc.
|
20
|
+
#sidebar
|
21
|
+
.block.notice#sidebar_block_notice= catch_content :sidebar_block_notice
|
22
|
+
.block#sidebar_block= catch_content :sidebar_block
|
23
|
+
.clear
|
data/config/init.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
#
|
2
|
+
# ==== Standalone Chefserver configuration
|
3
|
+
#
|
4
|
+
# This configuration/environment file is only loaded by bin/slice, which can be
|
5
|
+
# used during development of the slice. It has no effect on this slice being
|
6
|
+
# loaded in a host application. To run your slice in standalone mode, just
|
7
|
+
# run 'slice' from its directory. The 'slice' command is very similar to
|
8
|
+
# the 'merb' command, and takes all the same options, including -i to drop
|
9
|
+
# into an irb session for example.
|
10
|
+
#
|
11
|
+
# The usual Merb configuration directives and init.rb setup methods apply,
|
12
|
+
# including use_orm and before_app_loads/after_app_loads.
|
13
|
+
#
|
14
|
+
# If you need need different configurations for different environments you can
|
15
|
+
# even create the specific environment file in config/environments/ just like
|
16
|
+
# in a regular Merb application.
|
17
|
+
#
|
18
|
+
# In fact, a slice is no different from a normal # Merb application - it only
|
19
|
+
# differs by the fact that seamlessly integrates into a so called 'host'
|
20
|
+
# application, which in turn can override or finetune the slice implementation
|
21
|
+
# code and views.
|
22
|
+
#
|
23
|
+
|
24
|
+
$: << File.join(File.dirname(__FILE__), "..", "..", "chef", "lib")
|
25
|
+
require 'chef'
|
26
|
+
|
27
|
+
merb_gems_version = " > 1.0"
|
28
|
+
dependency "merb-assets", merb_gems_version
|
29
|
+
dependency "merb-helpers", merb_gems_version
|
30
|
+
dependency "chef", :immediate=>true unless defined?(Chef)
|
31
|
+
|
32
|
+
require 'rubygems'
|
33
|
+
|
34
|
+
Merb::Config.use do |c|
|
35
|
+
c[:session_id_key] = '_chef_server_session_id'
|
36
|
+
c[:session_secret_key] = Chef::Config.manage_secret_key
|
37
|
+
c[:session_store] = 'cookie'
|
38
|
+
c[:exception_details] = true
|
39
|
+
c[:reload_classes] = true
|
40
|
+
c[:log_level] = Chef::Config[:log_level]
|
41
|
+
if Chef::Config[:log_location].kind_of?(String)
|
42
|
+
c[:log_file] = Chef::Config[:log_location]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
data/config/router.rb
ADDED
@@ -0,0 +1,158 @@
|
|
1
|
+
if defined?(Merb::Plugins)
|
2
|
+
$:.unshift File.dirname(__FILE__)
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "..", "chef-solr", "lib")
|
4
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "..", "chef", "lib")
|
5
|
+
|
6
|
+
dependency 'merb-slices', :immediate => true
|
7
|
+
dependency 'chef', :immediate=>true unless defined?(Chef)
|
8
|
+
dependency 'bunny', :immediate=>true
|
9
|
+
dependency 'uuidtools', :immediate=>true
|
10
|
+
|
11
|
+
require 'chef/role'
|
12
|
+
require 'chef/data_bag'
|
13
|
+
require 'chef/data_bag_item'
|
14
|
+
require 'chef/api_client'
|
15
|
+
require 'chef/webui_user'
|
16
|
+
require 'chef/certificate'
|
17
|
+
|
18
|
+
require 'mixlib/authentication'
|
19
|
+
|
20
|
+
require 'chef/data_bag'
|
21
|
+
require 'chef/data_bag_item'
|
22
|
+
require 'ohai'
|
23
|
+
require 'openssl'
|
24
|
+
|
25
|
+
Merb::Plugins.add_rakefiles "chef-server-api/merbtasks", "chef-server-api/slicetasks", "chef-server-api/spectasks"
|
26
|
+
|
27
|
+
# Register the Slice for the current host application
|
28
|
+
Merb::Slices::register(__FILE__)
|
29
|
+
|
30
|
+
Merb.disable :json
|
31
|
+
|
32
|
+
# Slice configuration - set this in a before_app_loads callback.
|
33
|
+
# By default a Slice uses its own layout, so you can switch to
|
34
|
+
# the main application layout or no layout at all if needed.
|
35
|
+
#
|
36
|
+
# Configuration options:
|
37
|
+
# :layout - the layout to use; defaults to :chefserverslice
|
38
|
+
# :mirror - which path component types to use on copy operations; defaults to all
|
39
|
+
Merb::Slices::config[:chef_server_api][:layout] ||= :chef_server_api
|
40
|
+
|
41
|
+
# All Slice code is expected to be namespaced inside a module
|
42
|
+
module ChefServerApi
|
43
|
+
# Slice metadata
|
44
|
+
self.description = "ChefServerApi.. serving up some piping hot infrastructure!"
|
45
|
+
self.version = Chef::VERSION
|
46
|
+
self.author = "Opscode"
|
47
|
+
|
48
|
+
# Stub classes loaded hook - runs before LoadClasses BootLoader
|
49
|
+
# right after a slice's classes have been loaded internally.
|
50
|
+
def self.loaded
|
51
|
+
Chef::Log.info("Compiling routes... (totally normal to see 'Cannot find resource model')")
|
52
|
+
end
|
53
|
+
|
54
|
+
# Initialization hook - runs before AfterAppLoads BootLoader
|
55
|
+
def self.init
|
56
|
+
end
|
57
|
+
|
58
|
+
# Activation hook - runs after AfterAppLoads BootLoader
|
59
|
+
def self.activate
|
60
|
+
Mixlib::Authentication::Log.logger = Ohai::Log.logger = Chef::Log.logger
|
61
|
+
|
62
|
+
unless Merb::Config.environment == "test"
|
63
|
+
# create the couch design docs for nodes, roles, and databags
|
64
|
+
Chef::CouchDB.new.create_id_map
|
65
|
+
Chef::Node.create_design_document
|
66
|
+
Chef::Role.create_design_document
|
67
|
+
Chef::DataBag.create_design_document
|
68
|
+
Chef::ApiClient.create_design_document
|
69
|
+
Chef::WebUIUser.create_design_document
|
70
|
+
|
71
|
+
Chef::Log.info('Loading roles')
|
72
|
+
Chef::Role.sync_from_disk_to_couchdb
|
73
|
+
|
74
|
+
# Create the signing key and certificate
|
75
|
+
Chef::Certificate.generate_signing_ca
|
76
|
+
|
77
|
+
# Generate the validation key
|
78
|
+
Chef::Certificate.gen_validation_key
|
79
|
+
|
80
|
+
# Generate the Web UI Key
|
81
|
+
Chef::Certificate.gen_validation_key(Chef::Config[:web_ui_client_name], Chef::Config[:web_ui_key])
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Deactivation hook - triggered by Merb::Slices.deactivate(Chefserver)
|
86
|
+
def self.deactivate
|
87
|
+
end
|
88
|
+
|
89
|
+
# Setup routes inside the host application
|
90
|
+
#
|
91
|
+
# @param scope<Merb::Router::Behaviour>
|
92
|
+
# Routes will be added within this scope (namespace). In fact, any
|
93
|
+
# router behaviour is a valid namespace, so you can attach
|
94
|
+
# routes at any level of your router setup.
|
95
|
+
#
|
96
|
+
# @note prefix your named routes with :chefserverslice_
|
97
|
+
# to avoid potential conflicts with global named routes.
|
98
|
+
def self.setup_router(scope)
|
99
|
+
# Users
|
100
|
+
scope.resources :users
|
101
|
+
|
102
|
+
# Nodes
|
103
|
+
scope.resources :nodes, :id => /[^\/]+/
|
104
|
+
scope.match('/nodes/:id/cookbooks',
|
105
|
+
:id => /[^\/]+/,
|
106
|
+
:method => 'get').
|
107
|
+
to(:controller => "nodes", :action => "cookbooks")
|
108
|
+
# Roles
|
109
|
+
scope.resources :roles
|
110
|
+
|
111
|
+
# Status
|
112
|
+
scope.match("/status").to(:controller => "status", :action => "index").name(:status)
|
113
|
+
|
114
|
+
# Clients
|
115
|
+
scope.match("/clients", :method=>"post").to(:controller=>'clients', :action=>'create')
|
116
|
+
scope.match("/clients", :method=>"get").to(:controller=>'clients', :action=>'index').name(:clients)
|
117
|
+
scope.match("/clients/:id", :id => /[\w\.-]+/, :method=>"get").to(:controller=>'clients', :action=>'show').name(:client)
|
118
|
+
scope.match("/clients/:id", :id => /[\w\.-]+/, :method=>"put").to(:controller=>'clients', :action=>'update')
|
119
|
+
scope.match("/clients/:id", :id => /[\w\.-]+/, :method=>"delete").to(:controller=>'clients', :action=>'destroy')
|
120
|
+
|
121
|
+
# Search
|
122
|
+
scope.resources :search
|
123
|
+
scope.match('/search/reindex', :method => 'post').to(:controller => "search", :action => "reindex")
|
124
|
+
|
125
|
+
# Cookbooks
|
126
|
+
scope.match('/nodes/:id/cookbooks', :method => 'get').to(:controller => "nodes", :action => "cookbooks")
|
127
|
+
|
128
|
+
scope.resources :cookbooks
|
129
|
+
scope.match("/cookbooks/:cookbook_id/_content", :method => 'get', :cookbook_id => /[\w\.]+/).to(:controller => "cookbooks", :action => "get_tarball")
|
130
|
+
scope.match("/cookbooks/:cookbook_id/_content", :method => 'put', :cookbook_id => /[\w\.]+/).to(:controller => "cookbooks", :action => "update")
|
131
|
+
scope.match("/cookbooks/:cookbook_id/:segment", :cookbook_id => /[\w\.]+/).to(:controller => "cookbooks", :action => "show_segment").name(:cookbook_segment)
|
132
|
+
|
133
|
+
# Data
|
134
|
+
scope.match("/data/:data_bag_id/:id", :method => 'get').to(:controller => "data_item", :action => "show").name("data_bag_item")
|
135
|
+
scope.match("/data/:data_bag_id", :method => 'post').to(:controller => "data_item", :action => "create").name("create_data_bag_item")
|
136
|
+
scope.match("/data/:data_bag_id/:id", :method => 'put').to(:controller => "data_item", :action => "update").name("update_data_bag_item")
|
137
|
+
scope.match("/data/:data_bag_id/:id", :method => 'delete').to(:controller => "data_item", :action => "destroy").name("destroy_data_bag_item")
|
138
|
+
scope.resources :data
|
139
|
+
|
140
|
+
scope.match('/').to(:controller => 'main', :action =>'index').name(:top)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
|
145
|
+
# Setup the slice layout for ChefServerApi
|
146
|
+
#
|
147
|
+
# Use ChefServerApi.push_path and ChefServerApi.push_app_path
|
148
|
+
# to set paths to chefserver-level and app-level paths. Example:
|
149
|
+
#
|
150
|
+
# ChefServerApi.push_path(:application, ChefServerApi.root)
|
151
|
+
# ChefServerApi.push_app_path(:application, Merb.root / 'slices' / 'chefserverslice')
|
152
|
+
# ...
|
153
|
+
#
|
154
|
+
# Any component path that hasn't been set will default to ChefServerApi.root
|
155
|
+
#
|
156
|
+
# Or just call setup_default_structure! to setup a basic Merb MVC structure.
|
157
|
+
ChefServerApi.setup_default_structure!
|
158
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
namespace :slices do
|
2
|
+
namespace :chefserverslice do
|
3
|
+
|
4
|
+
desc "Install Chefserver"
|
5
|
+
task :install => [:preflight, :setup_directories, :copy_assets, :migrate]
|
6
|
+
|
7
|
+
desc "Test for any dependencies"
|
8
|
+
task :preflight do # see slicetasks.rb
|
9
|
+
end
|
10
|
+
|
11
|
+
desc "Setup directories"
|
12
|
+
task :setup_directories do
|
13
|
+
puts "Creating directories for host application"
|
14
|
+
ChefServerApi.mirrored_components.each do |type|
|
15
|
+
if File.directory?(ChefServerApi.dir_for(type))
|
16
|
+
if !File.directory?(dst_path = ChefServerApi.app_dir_for(type))
|
17
|
+
relative_path = dst_path.relative_path_from(Merb.root)
|
18
|
+
puts "- creating directory :#{type} #{File.basename(Merb.root) / relative_path}"
|
19
|
+
mkdir_p(dst_path)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# desc "Copy stub files to host application"
|
26
|
+
# task :stubs do
|
27
|
+
# puts "Copying stubs for ChefServerApi - resolves any collisions"
|
28
|
+
# copied, preserved = ChefServerApi.mirror_stubs!
|
29
|
+
# puts "- no files to copy" if copied.empty? && preserved.empty?
|
30
|
+
# copied.each { |f| puts "- copied #{f}" }
|
31
|
+
# preserved.each { |f| puts "! preserved override as #{f}" }
|
32
|
+
# end
|
33
|
+
|
34
|
+
# desc "Copy stub files and views to host application"
|
35
|
+
# task :patch => [ "stubs", "freeze:views" ]
|
36
|
+
|
37
|
+
desc "Copy public assets to host application"
|
38
|
+
task :copy_assets do
|
39
|
+
puts "Copying assets for ChefServerApi - resolves any collisions"
|
40
|
+
copied, preserved = ChefServerApi.mirror_public!
|
41
|
+
puts "- no files to copy" if copied.empty? && preserved.empty?
|
42
|
+
copied.each { |f| puts "- copied #{f}" }
|
43
|
+
preserved.each { |f| puts "! preserved override as #{f}" }
|
44
|
+
end
|
45
|
+
|
46
|
+
desc "Migrate the database"
|
47
|
+
task :migrate do # see slicetasks.rb
|
48
|
+
end
|
49
|
+
|
50
|
+
desc "Freeze ChefServerApi into your app (only chefserverslice/app)"
|
51
|
+
task :freeze => [ "freeze:app" ]
|
52
|
+
|
53
|
+
namespace :freeze do
|
54
|
+
|
55
|
+
# desc "Freezes ChefServerApi by installing the gem into application/gems"
|
56
|
+
# task :gem do
|
57
|
+
# ENV["GEM"] ||= "chefserverslice"
|
58
|
+
# Rake::Task['slices:install_as_gem'].invoke
|
59
|
+
# end
|
60
|
+
|
61
|
+
desc "Freezes ChefServerApi by copying all files from chefserverslice/app to your application"
|
62
|
+
task :app do
|
63
|
+
puts "Copying all chefserverslice/app files to your application - resolves any collisions"
|
64
|
+
copied, preserved = ChefServerApi.mirror_app!
|
65
|
+
puts "- no files to copy" if copied.empty? && preserved.empty?
|
66
|
+
copied.each { |f| puts "- copied #{f}" }
|
67
|
+
preserved.each { |f| puts "! preserved override as #{f}" }
|
68
|
+
end
|
69
|
+
|
70
|
+
desc "Freeze all views into your application for easy modification"
|
71
|
+
task :views do
|
72
|
+
puts "Copying all view templates to your application - resolves any collisions"
|
73
|
+
copied, preserved = ChefServerApi.mirror_files_for :view
|
74
|
+
puts "- no files to copy" if copied.empty? && preserved.empty?
|
75
|
+
copied.each { |f| puts "- copied #{f}" }
|
76
|
+
preserved.each { |f| puts "! preserved override as #{f}" }
|
77
|
+
end
|
78
|
+
|
79
|
+
desc "Freeze all models into your application for easy modification"
|
80
|
+
task :models do
|
81
|
+
puts "Copying all models to your application - resolves any collisions"
|
82
|
+
copied, preserved = ChefServerApi.mirror_files_for :model
|
83
|
+
puts "- no files to copy" if copied.empty? && preserved.empty?
|
84
|
+
copied.each { |f| puts "- copied #{f}" }
|
85
|
+
preserved.each { |f| puts "! preserved override as #{f}" }
|
86
|
+
end
|
87
|
+
|
88
|
+
desc "Freezes ChefServerApi as a gem and copies over chefserver/app"
|
89
|
+
task :app_with_gem => [:gem, :app]
|
90
|
+
|
91
|
+
desc "Freezes ChefServerApi by unpacking all files into your application"
|
92
|
+
task :unpack do
|
93
|
+
puts "Unpacking ChefServerApi files to your application - resolves any collisions"
|
94
|
+
copied, preserved = ChefServerApi.unpack_slice!
|
95
|
+
puts "- no files to copy" if copied.empty? && preserved.empty?
|
96
|
+
copied.each { |f| puts "- copied #{f}" }
|
97
|
+
preserved.each { |f| puts "! preserved override as #{f}" }
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
namespace :slices do
|
2
|
+
namespace :chefserverslice do
|
3
|
+
|
4
|
+
# add your own chefserver tasks here
|
5
|
+
|
6
|
+
# # Uncomment the following lines and edit the pre defined tasks
|
7
|
+
#
|
8
|
+
# # implement this to test for structural/code dependencies
|
9
|
+
# # like certain directories or availability of other files
|
10
|
+
# desc "Test for any dependencies"
|
11
|
+
# task :preflight do
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# # implement this to perform any database related setup steps
|
15
|
+
# desc "Migrate the database"
|
16
|
+
# task :migrate do
|
17
|
+
# end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
namespace :slices do
|
2
|
+
namespace :chefserverslice do
|
3
|
+
|
4
|
+
desc "Run slice specs within the host application context"
|
5
|
+
task :spec => [ "spec:explain", "spec:default" ]
|
6
|
+
|
7
|
+
namespace :spec do
|
8
|
+
|
9
|
+
slice_root = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
|
10
|
+
|
11
|
+
task :explain do
|
12
|
+
puts "\nNote: By running ChefServerApi specs inside the application context any\n" +
|
13
|
+
"overrides could break existing specs. This isn't always a problem,\n" +
|
14
|
+
"especially in the case of views. Use these spec tasks to check how\n" +
|
15
|
+
"well your application conforms to the original slice implementation."
|
16
|
+
end
|
17
|
+
|
18
|
+
Spec::Rake::SpecTask.new('default') do |t|
|
19
|
+
t.spec_opts = ["--format", "specdoc", "--colour"]
|
20
|
+
t.spec_files = Dir["#{slice_root}/spec/**/*_spec.rb"].sort
|
21
|
+
end
|
22
|
+
|
23
|
+
desc "Run all model specs, run a spec for a specific Model with MODEL=MyModel"
|
24
|
+
Spec::Rake::SpecTask.new('model') do |t|
|
25
|
+
t.spec_opts = ["--format", "specdoc", "--colour"]
|
26
|
+
if(ENV['MODEL'])
|
27
|
+
t.spec_files = Dir["#{slice_root}/spec/models/**/#{ENV['MODEL']}_spec.rb"].sort
|
28
|
+
else
|
29
|
+
t.spec_files = Dir["#{slice_root}/spec/models/**/*_spec.rb"].sort
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
desc "Run all request specs, run a spec for a specific request with REQUEST=MyRequest"
|
34
|
+
Spec::Rake::SpecTask.new('request') do |t|
|
35
|
+
t.spec_opts = ["--format", "specdoc", "--colour"]
|
36
|
+
if(ENV['REQUEST'])
|
37
|
+
t.spec_files = Dir["#{slice_root}/spec/requests/**/#{ENV['REQUEST']}_spec.rb"].sort
|
38
|
+
else
|
39
|
+
t.spec_files = Dir["#{slice_root}/spec/requests/**/*_spec.rb"].sort
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
desc "Run all specs and output the result in html"
|
44
|
+
Spec::Rake::SpecTask.new('html') do |t|
|
45
|
+
t.spec_opts = ["--format", "html"]
|
46
|
+
t.libs = ['lib', 'server/lib' ]
|
47
|
+
t.spec_files = Dir["#{slice_root}/spec/**/*_spec.rb"].sort
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,336 @@
|
|
1
|
+
* {margin:0;padding:0}
|
2
|
+
.clear { clear: both; height: 0; }
|
3
|
+
|
4
|
+
h1 { margin: 15px 0; font-size: 22px; font-weight: normal; }
|
5
|
+
h2 { font-size: 22px; margin: 15px 0; font-weight: normal;}
|
6
|
+
h3 { font-size: 18px; margin: 10px 0; font-weight: normal;}
|
7
|
+
h4 { font-size: 16px; margin: 10px 0; font-weight: normal;}
|
8
|
+
hr {height: 1px; border: 0; }
|
9
|
+
p { margin: 15px 0;}
|
10
|
+
a img { border: none; }
|
11
|
+
|
12
|
+
body {
|
13
|
+
font-size: 12px;
|
14
|
+
font-family: sans-serif;
|
15
|
+
}
|
16
|
+
|
17
|
+
#container {
|
18
|
+
min-width: 960px;
|
19
|
+
}
|
20
|
+
|
21
|
+
#header, #wrapper {
|
22
|
+
padding: 0 20px;
|
23
|
+
}
|
24
|
+
|
25
|
+
#header {
|
26
|
+
position: relative;
|
27
|
+
padding-top: 1px;
|
28
|
+
}
|
29
|
+
|
30
|
+
#header h1 {
|
31
|
+
margin: 0;
|
32
|
+
padding: 10px 0;
|
33
|
+
font-size: 30px;
|
34
|
+
}
|
35
|
+
|
36
|
+
#header h1 a:link, #header h1 a:active, #header h1 a:hover, #header h1 a:visited {
|
37
|
+
text-decoration: none;
|
38
|
+
}
|
39
|
+
|
40
|
+
#main {
|
41
|
+
width: 80%;
|
42
|
+
float: left;
|
43
|
+
}
|
44
|
+
|
45
|
+
.actions-bar {
|
46
|
+
padding: 10px 1px;
|
47
|
+
}
|
48
|
+
|
49
|
+
.actions-bar .actions {
|
50
|
+
float: left;
|
51
|
+
}
|
52
|
+
|
53
|
+
|
54
|
+
.actions-bar .pagination {
|
55
|
+
float: right;
|
56
|
+
padding: 1px 0;
|
57
|
+
}
|
58
|
+
|
59
|
+
#sidebar {
|
60
|
+
width: 15%;
|
61
|
+
float: right;
|
62
|
+
}
|
63
|
+
|
64
|
+
#sidebar h3 {
|
65
|
+
padding: 10px 15px;
|
66
|
+
margin: 0;
|
67
|
+
font-size: 13px;
|
68
|
+
}
|
69
|
+
|
70
|
+
#sidebar .block {
|
71
|
+
margin-bottom: 20px;
|
72
|
+
padding-bottom: 10px;
|
73
|
+
}
|
74
|
+
|
75
|
+
#sidebar .block .content {
|
76
|
+
padding: 0 15px;
|
77
|
+
}
|
78
|
+
|
79
|
+
#sidebar ul.navigation li a:link, #sidebar ul.navigation li a:visited {
|
80
|
+
display: block;
|
81
|
+
padding: 10px 15px;
|
82
|
+
}
|
83
|
+
|
84
|
+
#sidebar .block .sidebar-block, #sidebar .notice {
|
85
|
+
padding:10px;
|
86
|
+
}
|
87
|
+
|
88
|
+
#wrapper {
|
89
|
+
padding-top: 20px;
|
90
|
+
}
|
91
|
+
|
92
|
+
#main .block {
|
93
|
+
margin-bottom: 20px;
|
94
|
+
padding-top: 1px;
|
95
|
+
}
|
96
|
+
|
97
|
+
#main .block .content .inner {
|
98
|
+
padding: 0 15px 15px;
|
99
|
+
}
|
100
|
+
|
101
|
+
#main .main p.first {
|
102
|
+
margin-top: 0;
|
103
|
+
}
|
104
|
+
|
105
|
+
#user-navigation {
|
106
|
+
position: absolute;
|
107
|
+
top: 0px;
|
108
|
+
right: 20px;
|
109
|
+
}
|
110
|
+
|
111
|
+
#main-navigation {
|
112
|
+
width: 100%;
|
113
|
+
}
|
114
|
+
|
115
|
+
#user-navigation ul, #main-navigation ul, .secondary-navigation ul, #sidebar ul.navigation {
|
116
|
+
margin: 0;
|
117
|
+
padding: 0;
|
118
|
+
list-style-type: none;
|
119
|
+
}
|
120
|
+
|
121
|
+
#user-navigation ul li, #main-navigation ul li, .secondary-navigation ul li {
|
122
|
+
float: left;
|
123
|
+
}
|
124
|
+
|
125
|
+
#main-navigation ul li {
|
126
|
+
margin-right: 5px;
|
127
|
+
}
|
128
|
+
|
129
|
+
#user-navigation ul li {
|
130
|
+
padding: 5px 10px;
|
131
|
+
}
|
132
|
+
|
133
|
+
#main-navigation ul li a:link, #main-navigation ul li a:visited, #main-navigation ul li a:hover, #main-navigation ul li a:active,
|
134
|
+
.secondary-navigation ul li a:link, .secondary-navigation ul li a:visited, .secondary-navigation ul li a:hover, .secondary-navigation ul li a:active,
|
135
|
+
#user-navigation ul li a:link, #user-navigation ul li a:visited, #user-navigation ul li a:hover, #user-navigation ul li a:active {
|
136
|
+
text-decoration: none;
|
137
|
+
}
|
138
|
+
|
139
|
+
#main-navigation ul li a {
|
140
|
+
font-size: 15px;
|
141
|
+
display: block;
|
142
|
+
padding: 8px 15px;
|
143
|
+
}
|
144
|
+
|
145
|
+
.secondary-navigation {
|
146
|
+
font-size: 13px;
|
147
|
+
border-bottom-width: 10px;
|
148
|
+
border-bottom-style: solid;
|
149
|
+
}
|
150
|
+
|
151
|
+
.secondary-navigation ul li a {
|
152
|
+
display: block;
|
153
|
+
padding: 10px 15px;
|
154
|
+
}
|
155
|
+
|
156
|
+
#footer {
|
157
|
+
padding-bottom: 20px;
|
158
|
+
}
|
159
|
+
|
160
|
+
/* pagination */
|
161
|
+
|
162
|
+
.pagination a, .pagination span {
|
163
|
+
padding: 2px 5px;
|
164
|
+
margin-right: 5px;
|
165
|
+
display: block;
|
166
|
+
float: left;
|
167
|
+
border-style: solid;
|
168
|
+
border-width: 1px;
|
169
|
+
}
|
170
|
+
|
171
|
+
.pagination span.current {
|
172
|
+
font-weight: bold;
|
173
|
+
}
|
174
|
+
|
175
|
+
.pagination a {
|
176
|
+
text-decoration: none;
|
177
|
+
}
|
178
|
+
|
179
|
+
/* tables */
|
180
|
+
.table {
|
181
|
+
width: 100%;
|
182
|
+
border-collapse: collapse;
|
183
|
+
margin-bottom: 15px;
|
184
|
+
}
|
185
|
+
|
186
|
+
.table th {
|
187
|
+
padding: 10px;
|
188
|
+
font-weight: bold;
|
189
|
+
text-align: left;
|
190
|
+
}
|
191
|
+
|
192
|
+
.table th.first {
|
193
|
+
width: 30px;
|
194
|
+
}
|
195
|
+
|
196
|
+
.table th.last {
|
197
|
+
width: 200px;
|
198
|
+
}
|
199
|
+
|
200
|
+
.table .checkbox {
|
201
|
+
margin-left: 10px;
|
202
|
+
}
|
203
|
+
|
204
|
+
.table td {
|
205
|
+
padding: 10px;
|
206
|
+
}
|
207
|
+
|
208
|
+
.table td.last {
|
209
|
+
text-align: right;
|
210
|
+
}
|
211
|
+
|
212
|
+
/* forms */
|
213
|
+
|
214
|
+
input.checkbox {
|
215
|
+
margin: 0;
|
216
|
+
padding: 0;
|
217
|
+
}
|
218
|
+
|
219
|
+
.form .group {
|
220
|
+
margin-bottom: 15px;
|
221
|
+
}
|
222
|
+
|
223
|
+
.form div.left {
|
224
|
+
width: 20%;
|
225
|
+
float: left;
|
226
|
+
}
|
227
|
+
|
228
|
+
.form div.right {
|
229
|
+
width: 75%;
|
230
|
+
float: right;
|
231
|
+
}
|
232
|
+
|
233
|
+
.form .columns .column {
|
234
|
+
width: 48%;
|
235
|
+
}
|
236
|
+
|
237
|
+
.form .columns .left {
|
238
|
+
float: left;
|
239
|
+
}
|
240
|
+
|
241
|
+
.form .columns .right {
|
242
|
+
float: right;
|
243
|
+
}
|
244
|
+
|
245
|
+
.form label.label, .form input.text_field, .form textarea.text_area {
|
246
|
+
font-size: 1.2em;
|
247
|
+
padding: 1px 0;
|
248
|
+
margin: 0;
|
249
|
+
}
|
250
|
+
|
251
|
+
.form label.right {
|
252
|
+
text-align: right;
|
253
|
+
}
|
254
|
+
|
255
|
+
.form input.checkbox, .form input.radio {
|
256
|
+
margin-right: 5px;
|
257
|
+
}
|
258
|
+
|
259
|
+
.form label.checkbox, .form label.radio {
|
260
|
+
line-height: 1.5em;
|
261
|
+
}
|
262
|
+
|
263
|
+
.form label.label {
|
264
|
+
display: block;
|
265
|
+
padding-bottom: 2px;
|
266
|
+
font-weight: bold;
|
267
|
+
}
|
268
|
+
|
269
|
+
.form div.fieldWithErrors label.label {
|
270
|
+
display: inline;
|
271
|
+
}
|
272
|
+
|
273
|
+
.form .fieldWithErrors .error {
|
274
|
+
color: red;
|
275
|
+
}
|
276
|
+
|
277
|
+
.form input.text_field, .form textarea.text_area {
|
278
|
+
width: 100%;
|
279
|
+
border-width: 1px;
|
280
|
+
border-style: solid;
|
281
|
+
}
|
282
|
+
|
283
|
+
/* lists */
|
284
|
+
|
285
|
+
ul.list {
|
286
|
+
margin: 0;
|
287
|
+
padding: 0;
|
288
|
+
list-style-type: none;
|
289
|
+
}
|
290
|
+
|
291
|
+
ul.list li {
|
292
|
+
clear: left;
|
293
|
+
padding-bottom: 5px;
|
294
|
+
}
|
295
|
+
|
296
|
+
ul.list li .left {
|
297
|
+
float: left;
|
298
|
+
}
|
299
|
+
|
300
|
+
ul.list li .left .avatar {
|
301
|
+
width: 50px;
|
302
|
+
height: 50px;
|
303
|
+
}
|
304
|
+
|
305
|
+
ul.list li .item {
|
306
|
+
margin-left: 80px;
|
307
|
+
}
|
308
|
+
|
309
|
+
ul.list li .item .avatar {
|
310
|
+
float: left;
|
311
|
+
margin: 0 5px 5px 0;
|
312
|
+
width: 30px;
|
313
|
+
height: 30px;
|
314
|
+
}
|
315
|
+
|
316
|
+
/* box */
|
317
|
+
|
318
|
+
#box {
|
319
|
+
width: 500px;
|
320
|
+
margin: 50px auto;
|
321
|
+
}
|
322
|
+
|
323
|
+
#box .block {
|
324
|
+
margin-bottom: 20px;
|
325
|
+
}
|
326
|
+
|
327
|
+
#box .block h2 {
|
328
|
+
padding: 10px 15px;
|
329
|
+
margin: 0;
|
330
|
+
}
|
331
|
+
|
332
|
+
#box .block .content {
|
333
|
+
padding: 10px 20px;
|
334
|
+
}
|
335
|
+
|
336
|
+
|