chef-server-webui 0.9.18 → 0.10.0.beta.0

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 (68) hide show
  1. data/README.rdoc +0 -4
  2. data/Rakefile +10 -0
  3. data/app/controllers/application.rb +34 -6
  4. data/app/controllers/cookbooks.rb +125 -35
  5. data/app/controllers/environments.rb +235 -0
  6. data/app/controllers/nodes.rb +26 -19
  7. data/app/controllers/roles.rb +37 -44
  8. data/app/controllers/search.rb +13 -13
  9. data/app/helpers/application_helper.rb +34 -0
  10. data/app/views/cookbooks/_cookbook_content.html.haml +7 -0
  11. data/app/views/cookbooks/index.html.haml +22 -7
  12. data/app/views/cookbooks/show.html.haml +8 -50
  13. data/app/views/environments/_form.html.erb +91 -0
  14. data/app/views/environments/_navigation.html.haml +9 -0
  15. data/app/views/environments/_version_selector.html.erb +8 -0
  16. data/app/views/environments/edit.html.erb +17 -0
  17. data/app/views/environments/index.html.haml +26 -0
  18. data/app/views/environments/new.html.erb +17 -0
  19. data/app/views/environments/show.html.haml +31 -0
  20. data/app/views/layout/application.html.haml +22 -13
  21. data/app/views/layout/login.html.haml +2 -2
  22. data/app/views/nodes/_form.html.erb +69 -0
  23. data/app/views/nodes/index.html.haml +6 -2
  24. data/app/views/nodes/show.html.haml +4 -1
  25. data/app/views/roles/_form.html.erb +92 -0
  26. data/app/views/roles/_run_lists.html.erb +26 -0
  27. data/app/views/roles/edit.html.haml +1 -1
  28. data/app/views/roles/new.html.haml +1 -1
  29. data/app/views/roles/show.html.haml +10 -7
  30. data/app/views/status/index.html.haml +2 -1
  31. data/bin/chef-server-webui +1 -0
  32. data/config/router.rb +14 -8
  33. data/lib/chef-server-webui/version.rb +1 -1
  34. data/public/javascripts/chef.js +206 -49
  35. data/public/javascripts/cookbook_constraint_ctrl.js +191 -0
  36. data/public/javascripts/cookbook_versions.js +75 -0
  37. data/public/javascripts/jquery-1.4.4.min.js +167 -0
  38. data/public/javascripts/jquery.suggest.js +250 -0
  39. data/public/stylesheets/base.css +30 -24
  40. data/public/stylesheets/chef.css +212 -45
  41. data/public/stylesheets/jquery.suggest.css +28 -0
  42. data/public/stylesheets/jsonedit_main.css +26 -10
  43. data/public/stylesheets/themes/djime-cerulean/style.css +31 -18
  44. metadata +22 -29
  45. data/app/controllers/cookbook_attributes.rb +0 -41
  46. data/app/controllers/cookbook_definitions.rb +0 -41
  47. data/app/controllers/cookbook_files.rb +0 -39
  48. data/app/controllers/cookbook_libraries.rb +0 -41
  49. data/app/controllers/cookbook_recipes.rb +0 -40
  50. data/app/controllers/cookbook_templates.rb +0 -57
  51. data/app/helpers/cookbook_attributes_helper.rb +0 -7
  52. data/app/helpers/cookbook_definitions_helper.rb +0 -8
  53. data/app/helpers/cookbook_files_helper.rb +0 -8
  54. data/app/helpers/cookbook_libraries_helper.rb +0 -7
  55. data/app/helpers/cookbook_recipes_helper.rb +0 -8
  56. data/app/helpers/cookbook_templates_helper.rb +0 -8
  57. data/app/helpers/exceptions_helper.rb +0 -6
  58. data/app/helpers/global_helpers.rb +0 -39
  59. data/app/helpers/nodes_helper.rb +0 -43
  60. data/app/helpers/openid_consumer_helper.rb +0 -8
  61. data/app/helpers/openid_register_helper.rb +0 -8
  62. data/app/helpers/openid_server_helper.rb +0 -6
  63. data/app/helpers/openid_server_helpers.rb +0 -32
  64. data/app/helpers/roles_helper.rb +0 -5
  65. data/app/helpers/search_entries_helper.rb +0 -8
  66. data/app/helpers/search_helper.rb +0 -44
  67. data/app/views/nodes/_form.html.haml +0 -52
  68. data/app/views/roles/_form.html.haml +0 -52
@@ -0,0 +1,26 @@
1
+ <div class="runListWithControlsContainer <%= environment == @current_env ? 'active' : 'inactive' -%>" id="<%= environment %>">
2
+ <div class="sortable runListContainer">
3
+
4
+ <% run_list_class, empty_controls_class = run_list ? %w{active inactive} : %w{inactive active} -%>
5
+
6
+ <ul class="ui-sortable connectedSortable runListItemList <%= run_list_class -%>" id="<%= environment %>">
7
+ <% Array(run_list).each do |item| %>
8
+ <li id="<%=h(item)%>" class="<%= class_for_run_list_item(item) -%> runListItem"><%=h display_run_list_item(item)-%></li>
9
+ <% end %>
10
+ </ul>
11
+ <div class="emptyRunListControlsContainer <%= empty_controls_class -%>" id="<%=environment -%>">
12
+ <div class="cloneRunListTitle">This role has no environment specific run list for the (<%= environment -%>) environment.</div>
13
+ <div class="cloneRunListOption">
14
+ <a href="javascript:void(0)" class="createEmptyRunListControl" id="<%= environment -%>">Create a new empty run list</a>
15
+ </div>
16
+ <div class="cloneRunListOption">
17
+ Or, clone an existing run list: <%= select :environment_to_clone, :collection => @existing_run_list_environments, :id => environment, :class => 'environmentToClone' %>
18
+ </div>
19
+ </div>
20
+ </div>
21
+ <div class="runListAdditionalControls" id="<%= environment -%>">
22
+ <% if run_list && (environment != '_default')%>
23
+ <a href="javascript:void(0);" class="deleteEnvRunList" id="<%= environment -%>">Remove environment specific run list for <%= environment %></a>
24
+ <% end %>
25
+ </div>
26
+ </div>
@@ -3,4 +3,4 @@
3
3
  %h2.title= "Role #{h @role.name}"
4
4
  .inner
5
5
  = partial('navigation', :active => 'edit')
6
- = partial('form', :header => "Edit Role #{@role.name}", :form_id => 'edit_role', :submit_name => "Save Role", :submit_id => "edit_role_button", :form_for => 'edit', :form_url => url(:role, @role.name) )
6
+ = partial('form', :header => "Edit Role #{@role.name}", :form_id => 'edit_role', :submit_name => "Save Role", :submit_id => "edit_role_button", :form_for => 'edit', :form_url => url(:role, @role.name), :method => :put)
@@ -3,4 +3,4 @@
3
3
  %h2.title= "Role"
4
4
  .inner
5
5
  = partial('navigation', :active => 'create')
6
- = partial('form', :header => "Create new Role", :form_id => 'create_role', :submit_name => "Create Role", :submit_id => "create_role_button", :form_for => 'create', :form_url => url(:roles))
6
+ = partial('form', :header => "Create new Role", :form_id => 'create_role', :submit_name => "Create Role", :submit_id => "create_role_button", :method => :post, :form_for => 'create', :form_url => url(:roles))
@@ -10,24 +10,27 @@
10
10
  = @role.description
11
11
 
12
12
  .left
13
- %h3 Run List
13
+ %h3
14
+ = "Run List for Environment \"#{@current_env}\""
15
+ = @env_run_list_exists ? "" : "(_default)"
14
16
  %table.table
15
17
  %tr
16
18
  %th.first Position
17
19
  %th Name
20
+ %th Version
18
21
  %th.last Type
19
- - if @role.run_list.empty?
22
+ - if @run_list.empty?
20
23
  %tr
21
24
  %td{:colspan => 2} This role does not include any roles or recipes.
22
25
  - else
23
- -@role.run_list.each_with_index do |run_list_item, i|
26
+ -@run_list.each_with_index do |run_list_item, i|
24
27
  %tr
25
28
  %td.position= i
26
29
  %td= run_list_item.name
30
+ %td= run_list_item.version
27
31
  %td= run_list_item.type
28
32
  .left.accordion
29
33
  %h3.head= link_to("Recipes", "#")
30
- - recipes = @role.run_list.expand('server').recipes
31
34
  %div
32
35
  %span.description.form.help
33
36
  This is the list of recipes, fully expanded, as they will be applied to the node in question.
@@ -35,14 +38,14 @@
35
38
  %tr
36
39
  %th.first Position
37
40
  %th.last Name
38
- - if @role.run_list.empty?
41
+ - if @run_list.empty?
39
42
  %tr
40
43
  %td{:colspan => 2} This node has no recipes applied.
41
44
  - else
42
- - recipes.each_with_index do |recipe, i|
45
+ - @recipes.each_with_index do |recipe, i|
43
46
  %tr
44
47
  %td.position= i
45
- %td= recipes
48
+ %td= recipe
46
49
  .left
47
50
  %h3 Default Attributes
48
51
  = build_tree('defattrs', @role.default_attributes)
@@ -79,6 +79,7 @@
79
79
  %tr
80
80
  %th.first Position
81
81
  %th Name
82
+ %th Version
82
83
  %th.last Type
83
84
  %tbody
84
85
  - if node[1].run_list.empty?
@@ -89,5 +90,5 @@
89
90
  %tr
90
91
  %td.position= i
91
92
  %td= run_list_item.name
93
+ %td= run_list_item.version
92
94
  %td= run_list_item.type
93
-
@@ -28,6 +28,7 @@ require "merb-core"
28
28
 
29
29
  # Load chef and chef-server-api from source rather than gem, if present
30
30
  $:.unshift(File.expand_path(File.dirname(__FILE__) + '/../../chef/lib'))
31
+ $:.unshift(File.expand_path(File.dirname(__FILE__) + '/../../chef-solr/lib/'))
31
32
  $:.unshift(File.expand_path(File.dirname(__FILE__) + '/../lib'))
32
33
 
33
34
  # Print the version if we have -v or --version
data/config/router.rb CHANGED
@@ -19,9 +19,20 @@
19
19
 
20
20
  Merb::Router.prepare do
21
21
  resources :nodes, :id => /[^\/]+/
22
+ match("/nodes/_environments/:environment_id").to(:controller => "nodes", :action => "index").name(:nodes_by_environment)
23
+
22
24
  resources :clients, :id => /[^\/]+/
23
25
  resources :roles
24
26
 
27
+ resources :environments do |e|
28
+ e.match("/recipes", :method => "get").to(:controller=>"environments", :action=>"list_recipes")
29
+ e.match("/cookbooks").to(:contoller => "environments", :action => "list_cookbooks").name(:cookbooks)
30
+ e.match("/nodes").to(:controller => "environments", :action => "list_nodes").name(:nodes)
31
+ e.match("/select").to(:controller => "environments", :action => "select_environment").name(:select)
32
+ end
33
+
34
+ #match('/environments/create').to(:controller => "environments", :action => "create").name(:environments_create)
35
+
25
36
  match("/status").to(:controller => "status", :action => "index").name(:status)
26
37
 
27
38
  resources :searches, :path => "search", :controller => "search"
@@ -36,17 +47,12 @@ Merb::Router.prepare do
36
47
  match("/cookbooks/_recipe_files").to(:controller => "cookbooks", :action => "recipe_files")
37
48
  match("/cookbooks/_definition_files").to(:controller => "cookbooks", :action => "definition_files")
38
49
  match("/cookbooks/_library_files").to(:controller => "cookbooks", :action => "library_files")
50
+ match("/cookbooks/_environments/:environment_id").to(:controller => "cookbooks", :action => "index").name(:cookbooks_by_environment)
39
51
 
40
- match("/cookbooks/:cookbook_id/templates", :cookbook_id => /[\w\.]+/).to(:controller => "cookbook_templates", :action => "index")
41
- match("/cookbooks/:cookbook_id/libraries", :cookbook_id => /[\w\.]+/).to(:controller => "cookbook_libraries", :action => "index")
42
- match("/cookbooks/:cookbook_id/definitions", :cookbook_id => /[\w\.]+/).to(:controller => "cookbook_definitions", :action => "index")
43
- match("/cookbooks/:cookbook_id/recipes", :cookbook_id => /[\w\.]+/).to(:controller => "cookbook_recipes", :action => "index")
44
- match("/cookbooks/:cookbook_id/attributes", :cookbook_id => /[\w\.]+/).to(:controller => "cookbook_attributes", :action => "index")
45
- match("/cookbooks/:cookbook_id/files", :cookbook_id => /[\w\.]+/).to(:controller => "cookbook_files", :action => "index")
46
-
52
+ match("/cookbooks/:cookbook_id", :cookbook_id => /[\w\.]+/, :method => 'get').to(:controller => "cookbooks", :action => "cb_versions")
47
53
  match("/cookbooks/:cookbook_id/:cb_version", :cb_version => /[\w\.]+/, :method => 'get').to(:controller => "cookbooks", :action => "show").name(:show_specific_version_cookbook)
48
54
  resources :cookbooks
49
-
55
+
50
56
  resources :clients
51
57
 
52
58
  match("/databags/:databag_id/databag_items", :method => 'get').to(:controller => "databags", :action => "show", :id=>":databag_id")
@@ -1,3 +1,3 @@
1
1
  module ChefServerWebui
2
- VERSION = '0.9.18'
2
+ VERSION = '0.10.0.beta.0'
3
3
  end
@@ -7,9 +7,9 @@
7
7
  // Licensed under the Apache License, Version 2.0 (the "License");
8
8
  // you may not use this file except in compliance with the License.
9
9
  // You may obtain a copy of the License at
10
- //
10
+ //
11
11
  // http://www.apache.org/licenses/LICENSE-2.0
12
- //
12
+ //
13
13
  // Unless required by applicable law or agreed to in writing, software
14
14
  // distributed under the License is distributed on an "AS IS" BASIS,
15
15
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -17,23 +17,45 @@
17
17
  // limitations under the License.
18
18
  //
19
19
 
20
+
20
21
  $(document).ready(function(){
21
22
 
22
- $('form#edit_role, form#create_role').submit(function(event) {
23
- var form = $(this);
24
- var to_role = $('ul#for_role').sortable('toArray');
25
- if (form.attr('id') == 'edit_role') {
26
- form.append('<input type="hidden" name="_method" value="put">');
27
- }
28
- form.append($('input#role_name')).css('display', 'none');
29
- form.append($('textarea#role_description')).css('display', 'none');
23
+ var buildHiddenFormFromDragDrop = function(form, runListSet) {
24
+ runListSet.each(function(i, envRunListUl) {
25
+ runListItemList = $(envRunListUl).find('li.runListItem')
26
+ if(runListItemList.length == 0){
27
+ activeRunListUl = envRunListUl.getAttribute("class").split(" ").indexOf('active')
28
+ if(activeRunListUl >= 0){
29
+ form.append('<input type="hidden" name="env_run_lists[' + envRunListUl.id + ']"/>');
30
+ }
31
+ }
32
+ else{
33
+ runListItemList.each(function(i, field) {
34
+ form.append('<input type="hidden" name="env_run_lists[' + envRunListUl.id + '][]" value="' + field.id + '"/>');
35
+ });
36
+ }
37
+ });
38
+ };
39
+
40
+ var buildHiddenFormFromJSONEditor = function(form) {
30
41
  form.append('<input type="hidden" id="default_attributes" name="default_attributes"/>');
31
- $('input#default_attributes').attr('value', BCJTEP.save('json["defaults"]'))
42
+ $('input#default_attributes').attr('value', BCJTEP.save('json["defaults"]'));
32
43
  form.append('<input type="hidden" id="override_attributes" name="override_attributes"/>');
33
44
  $('input#override_attributes').attr('value', BCJTEP.save('json["overrides"]'));
34
- jQuery.each(to_role, function(i, field) {
35
- form.append('<input type="hidden" name="for_role[]" value="' + field + '"/>');
36
- });
45
+ };
46
+
47
+ $('a#debugFormBuild').click(function(event) {buildHiddenFormFromDragDrop(event)});
48
+
49
+
50
+ $('form.roleForm').submit(function(event) {
51
+ buildHiddenFormFromDragDrop($(this), $('ul.runListItemList'));
52
+ buildHiddenFormFromJSONEditor($(this));
53
+ });
54
+
55
+ $('form#edit_environment, form#create_environment').submit(function(event) {
56
+ var form = $(this);
57
+ form.append('<input type="hidden" id="attributes" name="attributes"/>');
58
+ $('input#attributes').attr('value', BCJTEP.save('json'))
37
59
  });
38
60
 
39
61
  $('form#edit_node, form#create_node').submit(function(event) {
@@ -59,7 +81,7 @@ $(document).ready(function(){
59
81
  form.append($('input#json_data').attr('value', BCJTEP.save()));
60
82
  });
61
83
 
62
- $('form#edit_databag, form#create_databag').submit(function(event) {
84
+ $('form#edit_databag, form#create_databag').submit(function(event) {
63
85
  var form = $(this);
64
86
  if (form.attr('id') == 'edit_databag') {
65
87
  form.append('<input type="hidden" name="_method" value="put">');
@@ -84,77 +106,212 @@ $(document).ready(function(){
84
106
  var form = $(this);
85
107
  if (form.attr('id') == 'edit_user') {
86
108
  form.append('<input type="hidden" name="_method" value="put">');
87
- form.append($('input#user_new_password')).css('display', 'none');
88
- form.append($('input#user_admin')).css('display', 'none');
89
- form.append($('input#user_confirm_new_password')).css('display', 'none');
90
- form.append($('input#openid')).css('display', 'none');
91
- }
92
- if (form.attr('id') == 'login') {
93
- form.append($('input#user_name')).css('display', 'none');
94
- form.append($('input#password')).css('display', 'none');
95
- }
109
+ form.append($('input#user_new_password')).css('display', 'none');
110
+ form.append($('input#user_admin')).css('display', 'none');
111
+ form.append($('input#user_confirm_new_password')).css('display', 'none');
112
+ form.append($('input#openid')).css('display', 'none');
113
+ }
114
+ if (form.attr('id') == 'login') {
115
+ form.append($('input#user_name')).css('display', 'none');
116
+ form.append($('input#password')).css('display', 'none');
117
+ }
96
118
  });
97
119
 
98
120
  // livequery hidden form for link_to ajax magic
99
121
  $('a[method]').livequery(function(){
100
122
  var message = $(this).attr('confirm');
101
123
  var method = $(this).attr('method');
102
-
124
+
103
125
  if (!method && !message) return;
104
-
126
+
105
127
  $(this).click(function(event){
106
128
  if (message && !confirm(message)) {
107
129
  event.preventDefault();
108
130
  return;
109
131
  }
110
-
111
- if (method == 'post' || method == 'put' || method == 'delete') {
132
+
133
+ if (method === 'post' || method === 'put' || method === 'delete') {
112
134
  event.preventDefault();
113
135
  var form = $("<form/>").attr('method', 'post').attr('action', this.href).attr('style', 'display: none');
114
- if (method != "post") {
136
+ if (method !== "post") {
115
137
  form.append($('<input type="hidden" name="_method"/>').attr('value', method));
116
138
  }
117
139
  form.insertAfter(this).submit();
118
140
  }
119
141
  });
120
142
  });
121
-
143
+
122
144
  // accordion for the cookbooks show view
123
- $('.accordion .head').click(function() {
124
- $(this).next().toggle('slow');
125
- return false;
126
- }).next().hide();
127
-
128
- // global facebox callback
129
- $('a[rel*=facebox]').facebox();
130
-
131
-
132
- $('.connectedSortable').sortable({
133
- placeholder: 'ui-state-highlight',
134
- connectWith: $('.connectedSortable')
135
- }).disableSelection();
145
+ $('.accordion .head').click(function() {
146
+ $(this).next().toggle('slow');
147
+ return false;
148
+ }).next().hide();
149
+
150
+ // global facebox callback
151
+ $('a[rel*=facebox]').facebox();
152
+
153
+
154
+ var enableDragDropBehavior = function() {
155
+ $('.connectedSortable').sortable({
156
+ placeholder: 'ui-state-highlight',
157
+ connectWith: $('.connectedSortable')
158
+ }).disableSelection();
159
+ };
160
+
161
+ var disableDragDropBehavior = function() {
162
+ $('.connectedSortable').sortable("destroy");
163
+ };
164
+
165
+ enableDragDropBehavior();
136
166
 
137
167
  // The table tree!
138
168
  $('table.tree').treeTable({ expandable: true });
139
169
  $('span.expander').click(function() { $('tr#' + $(this).attr('toggle')).toggleBranch(); });
140
-
170
+
141
171
  // Tooltips
142
- $("div.tooltip").tooltip({
172
+ $("div.tooltip").tooltip({
143
173
  position: ['center', 'right'],
144
174
  offset: [-5, 10],
145
175
  effect: 'toggle',
146
- opacity: 0.7
176
+ opacity: 0.7
147
177
  });
148
-
178
+
149
179
  // Show the sidebars if they have text in them!
150
180
  var sidebar_block_notice_children = $("#sidebar_block_notice").children().length;
151
181
  var sidebar_block_children = $("#sidebar_block").children().length;
152
-
182
+
153
183
  if (sidebar_block_notice_children > 0) {
154
184
  $("#sidebar_block_notice").fadeIn();
155
185
  }
156
-
186
+
157
187
  if (sidebar_block_children > 0) {
158
188
  $("#sidebar_block").fadeIn();
159
189
  }
190
+
191
+ // Run list editor with per-env run lists for roles
192
+
193
+ var populateAvailableRecipesForEnv = function(currentEnvironment, callback) {
194
+ $.getJSON('/environments/' + currentEnvironment + '/recipes', function(data) {
195
+ $('div#available_recipes_container .spinner').hide();
196
+ for (var i=0; i < data['recipes'].length; i++) {
197
+ var recipe = data['recipes'][i];
198
+ $('ul.availableRecipes').append('<li id="recipe[' + recipe + ']" class="ui-state-default runListItem">' + recipe + '</li>');
199
+ }
200
+ });
201
+ if (callback) { callback(); }
202
+ };
203
+
204
+ var depopulateAvailableRecipesForEnv = function() {
205
+ $('ul.availableRecipes li').remove();
206
+ $('div#available_recipes_container .spinner').show();
207
+ };
208
+
209
+ // If the attribute 'data-initial-env' exists on this element, use it to load
210
+ // the recipes for that environment via ajax.
211
+ var initialEnvironment = $('div#environmentRunListSelector').data('initial-env');
212
+ if (initialEnvironment) {
213
+ populateAvailableRecipesForEnv(initialEnvironment);
214
+ }
215
+
216
+ var resetAvailableRoleList = function() {
217
+ $('ul#availableRoles li').remove();
218
+ var allRoles = $('ul#availableRoles').data('role-list');
219
+ for (var i=0; i < allRoles.length; i++) {
220
+ var role = allRoles[i];
221
+ $('ul#availableRoles').append('<li id="role[' + role + ']" class="ui-state-highlight runListItem">' + role + '</li>');
222
+ }
223
+
224
+ };
225
+
226
+ var clearRunListFor = function(environment) {
227
+ $('ul.runListItemList#' + environment).children().remove();
228
+ };
229
+
230
+ var removeEnvironmentFromCloneControls = function(environment) {
231
+ $('select.environmentToClone option[value="' + environment + '"]').remove();
232
+ };
233
+
234
+ var addEnvironmentToCloneControls = function(environment) {
235
+ $('select.environmentToClone').append('<option value="' + environment + '">' + environment + '</option>');
236
+ };
237
+
238
+ var deleteEnvRunList = function(environment) {
239
+ clearRunListFor(environment);
240
+ $('ul.runListItemList#' + environment).removeClass('active').addClass('inactive');
241
+ $('div.emptyRunListControlsContainer#' + environment).removeClass('inactive').addClass('active');
242
+ $('div.runListAdditionalControls#' + environment + " a").remove();
243
+ removeEnvironmentFromCloneControls(environment);
244
+ };
245
+
246
+ var createRunListDeleteLinkFor = function(environment) {
247
+ // remove any existing link
248
+ $('a.deleteEnvRunList#' + environment).remove();
249
+ var containerDiv = $('div.runListAdditionalControls#' + environment);
250
+ var link = '<a href="javascript:void(0);" class="deleteEnvRunList" id="' + environment + '">Remove environment specific run list for ' + environment + '</a>';
251
+ containerDiv.append(link);
252
+ containerDiv.find('a').click(function(j) {deleteEnvRunList(environment);});
253
+ };
254
+
255
+ $('a.createEmptyRunListControl').each(function(i) {
256
+ var environment = $(this).attr('id');
257
+ $(this).click(function(event) {
258
+ $('div.emptyRunListControlsContainer#' + environment).removeClass('active').addClass('inactive');
259
+ var runListContainerForEnv = $('div.runListContainer#' + environment + 'RunListContainer');
260
+ $('ul.runListItemList#' + environment).removeClass('inactive').addClass('active');
261
+ // remove all previous drag/drop events/behavior/whatever, then re-add it for the new run list container
262
+ disableDragDropBehavior();
263
+ enableDragDropBehavior();
264
+ createRunListDeleteLinkFor(environment);
265
+ addEnvironmentToCloneControls(environment);
266
+ });
267
+ });
268
+
269
+ var setActiveRunListLabelFor = function(environment) {
270
+ var labelElement = $('span#selectedRunListEditorLabel');
271
+ if (environment === '_default') {
272
+ labelElement.html('Default Run List');
273
+ }
274
+ else {
275
+ labelElement.html('Run List for ' + environment);
276
+ }
277
+ };
278
+
279
+ $('a.deleteEnvRunList').each(function(i) {
280
+ var environment = $(this).attr('id');
281
+ $(this).click(function(j) {deleteEnvRunList(environment);});
282
+ });
283
+
284
+ $('select#activeEnvironment').change(function() {
285
+ // set the active run list editor
286
+ var newActiveEnvironment = $(this).val();
287
+ if (newActiveEnvironment !== 'noop') {
288
+ $('div.runListWithControlsContainer.active').removeClass('active').addClass('inactive');
289
+ $('div.runListWithControlsContainer#' + newActiveEnvironment).addClass('active', 10000).removeClass('inactive');
290
+ setActiveRunListLabelFor(newActiveEnvironment);
291
+ depopulateAvailableRecipesForEnv();
292
+ var selector = $(this);
293
+ populateAvailableRecipesForEnv(newActiveEnvironment, function() { selector.val('noop');});
294
+ resetAvailableRoleList();
295
+ }
296
+ });
297
+
298
+ $('select.environmentToClone').change(function() {
299
+ var environmentToClone = $(this).val();
300
+ var targetEnvironment = $(this).attr('id');
301
+ var targetRunList = $('ul.runListItemList#' + targetEnvironment);
302
+ clearRunListFor(targetEnvironment); // be sure we start with a clean slate
303
+ $('ul.runListItemList#' + environmentToClone).children().clone().appendTo(targetRunList);
304
+ $('ul.runListItemList#' + targetEnvironment).removeClass('inactive').addClass('active');
305
+ $('div.emptyRunListControlsContainer#' + targetEnvironment).removeClass('active').addClass('inactive');
306
+ createRunListDeleteLinkFor(targetEnvironment);
307
+ addEnvironmentToCloneControls(targetEnvironment);
308
+ });
309
+
310
+ $('select#nodeEnvironment').change(function() {
311
+ // set the active run list editor
312
+ var newNodeEnvironment = $(this).val();
313
+ depopulateAvailableRecipesForEnv();
314
+ populateAvailableRecipesForEnv(newNodeEnvironment);
315
+ });
316
+
160
317
  });