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.
Files changed (49) hide show
  1. data/LICENSE +201 -0
  2. data/README.rdoc +92 -0
  3. data/Rakefile +59 -0
  4. data/app/controllers/application.rb +289 -0
  5. data/app/controllers/clients.rb +111 -0
  6. data/app/controllers/cookbooks.rb +213 -0
  7. data/app/controllers/data.rb +75 -0
  8. data/app/controllers/data_item.rb +108 -0
  9. data/app/controllers/exceptions.rb +40 -0
  10. data/app/controllers/main.rb +18 -0
  11. data/app/controllers/nodes.rb +102 -0
  12. data/app/controllers/roles.rb +73 -0
  13. data/app/controllers/search.rb +60 -0
  14. data/app/controllers/users.rb +77 -0
  15. data/app/helpers/application_helper.rb +163 -0
  16. data/app/helpers/exceptions_helper.rb +6 -0
  17. data/app/helpers/global_helpers.rb +25 -0
  18. data/app/helpers/nodes_helper.rb +26 -0
  19. data/app/helpers/roles_helper.rb +5 -0
  20. data/app/helpers/tarball_helper.rb +82 -0
  21. data/app/views/exceptions/bad_request.json.erb +1 -0
  22. data/app/views/exceptions/internal_server_error.html.erb +216 -0
  23. data/app/views/exceptions/not_acceptable.html.haml +5 -0
  24. data/app/views/exceptions/not_found.html.erb +47 -0
  25. data/app/views/exceptions/standard_error.html.erb +217 -0
  26. data/app/views/layout/chef_server_api.html.haml +23 -0
  27. data/app/views/main/index.html.haml +5 -0
  28. data/config/init.rb +45 -0
  29. data/config/router.rb +6 -0
  30. data/lib/chef-server-api.rb +158 -0
  31. data/lib/chef-server-api/merbtasks.rb +103 -0
  32. data/lib/chef-server-api/slicetasks.rb +20 -0
  33. data/lib/chef-server-api/spectasks.rb +53 -0
  34. data/public/images/avatar.png +0 -0
  35. data/public/images/indicator.gif +0 -0
  36. data/public/images/merb.jpg +0 -0
  37. data/public/stylesheets/base.css +336 -0
  38. data/public/stylesheets/chef.css +157 -0
  39. data/public/stylesheets/themes/bec-green/style.css +290 -0
  40. data/public/stylesheets/themes/bec/style.css +301 -0
  41. data/public/stylesheets/themes/blue/style.css +280 -0
  42. data/public/stylesheets/themes/default/style.css +267 -0
  43. data/public/stylesheets/themes/djime-cerulean/style.css +298 -0
  44. data/public/stylesheets/themes/kathleene/style.css +272 -0
  45. data/public/stylesheets/themes/orange/style.css +263 -0
  46. data/public/stylesheets/themes/reidb-greenish/style.css +301 -0
  47. data/stubs/app/controllers/application.rb +2 -0
  48. data/stubs/app/controllers/main.rb +2 -0
  49. 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
@@ -0,0 +1,5 @@
1
+ .block#block-text
2
+ .content
3
+ %h2.title The REST API
4
+ .inner
5
+ This is the top of the Chef Server REST API. It's not really explorable via a web browser.
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,6 @@
1
+ # This file is here so slice can be testing as a stand alone application.
2
+
3
+ #Merb::Router.prepare do
4
+ # resources :roles
5
+ # ...
6
+ #end
@@ -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
+