foreman_docker 2.0.1 → 2.1.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 (81) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/foreman_docker/image_step.js +17 -16
  3. data/app/assets/stylesheets/foreman_docker/autocomplete.css.scss +2 -2
  4. data/app/controllers/api/v2/containers_controller.rb +23 -15
  5. data/app/controllers/containers/steps_controller.rb +3 -3
  6. data/app/controllers/containers_controller.rb +17 -19
  7. data/app/helpers/container_steps_helper.rb +5 -1
  8. data/app/helpers/containers_helper.rb +5 -7
  9. data/app/models/concerns/fog_extensions/fogdocker/server.rb +1 -1
  10. data/app/models/docker_registry.rb +16 -4
  11. data/app/models/foreman_docker/docker.rb +2 -1
  12. data/app/models/service/containers.rb +1 -1
  13. data/app/overrides/remove_docker_from_compute_profiles.rb +14 -0
  14. data/app/overrides/rename_virtual_machines_containers.rb +10 -0
  15. data/app/services/foreman_docker/container_remover.rb +20 -0
  16. data/app/views/containers/index.html.erb +4 -7
  17. data/app/views/containers/show.html.erb +2 -2
  18. data/app/views/containers/steps/_image_hub_tab.html.erb +41 -40
  19. data/app/views/foreman_docker/common_parameters/_dns_entry.html.erb +2 -2
  20. data/app/views/foreman_docker/common_parameters/_environment_variable.html.erb +2 -2
  21. data/app/views/foreman_docker/common_parameters/_exposed_port.html.erb +1 -1
  22. data/app/views/registries/index.html.erb +7 -7
  23. data/config/routes.rb +1 -1
  24. data/db/migrate/20141209182008_remove_docker_tables.rb +8 -2
  25. data/lib/foreman_docker/engine.rb +1 -0
  26. data/lib/foreman_docker/version.rb +1 -1
  27. data/locale/Makefile +58 -4
  28. data/locale/de/LC_MESSAGES/foreman_docker.mo +0 -0
  29. data/locale/de/foreman_docker.edit.po +631 -0
  30. data/locale/de/foreman_docker.po +110 -78
  31. data/locale/de/foreman_docker.po.time_stamp +0 -0
  32. data/locale/es/LC_MESSAGES/foreman_docker.mo +0 -0
  33. data/locale/es/foreman_docker.edit.po +631 -0
  34. data/locale/es/foreman_docker.po +110 -78
  35. data/locale/es/foreman_docker.po.time_stamp +0 -0
  36. data/locale/foreman_docker.pot +414 -219
  37. data/locale/fr/LC_MESSAGES/foreman_docker.mo +0 -0
  38. data/locale/fr/foreman_docker.edit.po +632 -0
  39. data/locale/fr/foreman_docker.po +111 -84
  40. data/locale/fr/foreman_docker.po.time_stamp +0 -0
  41. data/locale/it/LC_MESSAGES/foreman_docker.mo +0 -0
  42. data/locale/it/foreman_docker.edit.po +630 -0
  43. data/locale/it/foreman_docker.po +110 -82
  44. data/locale/it/foreman_docker.po.time_stamp +0 -0
  45. data/locale/ja/LC_MESSAGES/foreman_docker.mo +0 -0
  46. data/locale/ja/foreman_docker.edit.po +634 -0
  47. data/locale/ja/foreman_docker.po +109 -64
  48. data/locale/ja/foreman_docker.po.time_stamp +0 -0
  49. data/locale/ko/LC_MESSAGES/foreman_docker.mo +0 -0
  50. data/locale/ko/foreman_docker.edit.po +629 -0
  51. data/locale/ko/foreman_docker.po +108 -65
  52. data/locale/ko/foreman_docker.po.time_stamp +0 -0
  53. data/locale/pt_BR/LC_MESSAGES/foreman_docker.mo +0 -0
  54. data/locale/pt_BR/foreman_docker.edit.po +631 -0
  55. data/locale/pt_BR/foreman_docker.po +109 -74
  56. data/locale/pt_BR/foreman_docker.po.time_stamp +0 -0
  57. data/locale/ru/LC_MESSAGES/foreman_docker.mo +0 -0
  58. data/locale/ru/foreman_docker.edit.po +630 -0
  59. data/locale/ru/foreman_docker.po +110 -72
  60. data/locale/ru/foreman_docker.po.time_stamp +0 -0
  61. data/locale/zanata.xml +3 -3
  62. data/locale/zh_CN/LC_MESSAGES/foreman_docker.mo +0 -0
  63. data/locale/zh_CN/foreman_docker.edit.po +628 -0
  64. data/locale/zh_CN/foreman_docker.po +108 -64
  65. data/locale/zh_CN/foreman_docker.po.time_stamp +0 -0
  66. data/locale/zh_TW/LC_MESSAGES/foreman_docker.mo +0 -0
  67. data/locale/zh_TW/foreman_docker.edit.po +628 -0
  68. data/locale/zh_TW/foreman_docker.po +108 -65
  69. data/locale/zh_TW/foreman_docker.po.time_stamp +0 -0
  70. data/test/factories/docker_registry.rb +4 -0
  71. data/test/functionals/api/v2/containers_controller_test.rb +18 -4
  72. data/test/functionals/api/v2/registries_controller_test.rb +2 -0
  73. data/test/functionals/containers_controller_test.rb +56 -8
  74. data/test/integration/container_steps_test.rb +1 -1
  75. data/test/integration/container_test.rb +1 -1
  76. data/test/units/container_remover_test.rb +31 -0
  77. data/test/units/container_test.rb +6 -0
  78. data/test/units/containers_service_test.rb +2 -0
  79. data/test/units/docker_registry_test.rb +20 -3
  80. data/test/units/foreman_docker/docker_test.rb +10 -0
  81. metadata +57 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 12e42c771f843e87d2ee36bec11487a4c3336c90
4
- data.tar.gz: a81664dbe8b7001f0a7fe7d90fe6ae4acbf5de58
3
+ metadata.gz: dc562486af7545e9340afe42f3742eae15811824
4
+ data.tar.gz: f538d659b2bec681e978a943de4a19fb4c9259c1
5
5
  SHA512:
6
- metadata.gz: a1db2612e76589521267a1ba5ef5a01aaa8b9f865b1d3b5049ae5e13acdfc48f4dad97b5179f9d2d403202098123edb522bfcb71dd496ac665d6178736be0bd9
7
- data.tar.gz: 07339351f2555cf31cf7f44d1c28fa14a200ed327da0e41d715228f30bf2fdddfdba7af37551252cb502ae0ad08e164a34ed864dc33c56277fa7ee4189ed3da1
6
+ metadata.gz: 305bcea8f11eb23bb65ffb2969696fc8d0e08319d433677747413a088cd688e142fd7dfda8c31547cf194b5166b15358254f5eff0b262b722ace97e0baa1213a
7
+ data.tar.gz: 1d886a2caa3a372445c8d5c5f1e554c0456f183701387928930b95dd9a4c143fa2da9994b65b4e9d00c808f6cc1b35fbfa4476e25f62a769df9768de5e086f53
@@ -27,27 +27,28 @@ function setupAutoComplete(registryType) {
27
27
  }
28
28
 
29
29
  function autoCompleteRepo(item) {
30
+ var registryType = $(item).data('registry'),
31
+ search_add_on = getImageConfirmation(registryType),
32
+ tag = getTag(registryType);
33
+
34
+ // Patternfly spinner uses 'float: left' and moves it to the left of the
35
+ // search button. Instead, we use FontAwesome's spinner to keep it at
36
+ // the right.
37
+ search_add_on.attr('class', 'fa fa-spin fa-circle-o-notch');
38
+
30
39
  $.ajax({
31
40
  type:'get',
32
41
  url: $(item).attr('data-url'),
33
42
  data: { search: item.val(), registry_id: $('#docker_container_wizard_states_image_registry_id').val() },
34
- //data:'search=' + item.val(),
35
43
  success:function (result) {
36
- var registryType = $(item).data('registry'),
37
- search_add_on = getSearchAddOn(registryType),
38
- tag = getTag(registryType);
39
- if(result == 'true'){
44
+ if(result == 'true'){
40
45
  search_add_on.attr('title', 'Image found in the compute resource');
41
- search_add_on.removeClass('glyphicon-remove');
42
- search_add_on.css('color', 'lightgreen');
43
- search_add_on.addClass('glyphicon-ok');
46
+ search_add_on.attr('class', 'pficon pficon-ok');
44
47
  setWaitingText('Image found: <strong>' + item.val() + '</strong>. Retrieving available tags, please wait...', registryType);
45
48
  setAutocompleteTags(registryType);
46
49
  } else {
47
50
  search_add_on.attr('title', 'Image NOT found in the compute resource');
48
- search_add_on.removeClass('glyphicon-ok');
49
- search_add_on.css('color', 'red');
50
- search_add_on.addClass('glyphicon-remove');
51
+ search_add_on.attr('class', 'pficon pficon-error-circle-o');
51
52
  tag.autocomplete('option', 'source', []);
52
53
  }
53
54
  },
@@ -59,13 +60,13 @@ function autoCompleteRepo(item) {
59
60
 
60
61
  function setAutocompleteTags(registryType) {
61
62
  var tag = getTag(registryType);
62
- tag.addClass('tags-autocomplete-loading');
63
+ tag.addClass('spinner-label');
63
64
  tag.val('');
64
65
  var source = [];
65
66
  $.getJSON( tag.data("url"), { search: getRepo(registryType).val(), registry_id: $('#docker_container_wizard_states_image_registry_id').val() },
66
67
  function(data) {
67
68
  getSearchSpinner(registryType).hide();
68
- tag.removeClass('tags-autocomplete-loading');
69
+ tag.removeClass('spinner-label');
69
70
  $.each( data, function(index, value) {
70
71
  source.push({label: value.label, value: value.value});
71
72
  });
@@ -135,10 +136,10 @@ function getRepositorySearchResults(registryType) {
135
136
  return $('form[data-registry="' + registryType + '"] [data-repository-search-results]:first');
136
137
  }
137
138
 
138
- function getSearchAddOn(registryType) {
139
- return $('form[data-registry="' + registryType + '"] [data-search-addon]:first');
139
+ function getImageConfirmation(registryType) {
140
+ return $('form[data-registry="' + registryType + '"] #image-confirmation');
140
141
  }
141
142
 
142
143
  function getWaitText(registryType) {
143
144
  return $('form[data-registry="' + registryType + '"] [data-wait-text]:first');
144
- }
145
+ }
@@ -1,3 +1,3 @@
1
- .tags-autocomplete-loading {
2
- background: white url('spinner.gif') right center no-repeat;
1
+ #image-confirmation {
2
+ margin-left: 10px;
3
3
  }
@@ -12,7 +12,7 @@ module Api
12
12
 
13
13
  api :GET, '/containers/', N_('List all containers')
14
14
  api :GET, '/compute_resources/:compute_resource_id/containers/',
15
- N_('List all containers in a compute resource')
15
+ N_('List all containers on a compute resource')
16
16
  param :compute_resource_id, :identifier
17
17
  param_group :search_and_pagination, ::Api::V2::BaseController
18
18
 
@@ -28,7 +28,7 @@ module Api
28
28
 
29
29
  api :GET, '/containers/:id/', N_('Show a container')
30
30
  api :GET, '/compute_resources/:compute_resource_id/containers/:id',
31
- N_('Show container in a compute resource')
31
+ N_('Show container on a compute resource')
32
32
  param :id, :identifier, :required => true
33
33
  param :compute_resource_id, :identifier
34
34
 
@@ -40,13 +40,13 @@ module Api
40
40
  param :name, String
41
41
  param_group :taxonomies, ::Api::V2::BaseController
42
42
  param :compute_resource_id, :identifier, :required => true
43
- param :registry_id, :identifier, :desc => N_('Registry this container will have to
44
- use to get the image')
43
+ param :registry_id, :identifier, :desc => N_('Registry this container will have to ' +
44
+ 'use to get the image')
45
45
  param :repository_name, String, :required => true,
46
- :desc => N_('Name of the repository to use
47
- to create the container. e.g: centos')
46
+ :desc => N_('Name of the repository to use ' +
47
+ 'to create the container. e.g. centos')
48
48
  param :tag, String, :required => true,
49
- :desc => N_('Tag to use to create the container. e.g: latest')
49
+ :desc => N_('Tag to use to create the container. e.g. latest')
50
50
  param :tty, :bool
51
51
  param :entrypoint, String
52
52
  param :command, String, :required => true
@@ -57,15 +57,15 @@ module Api
57
57
  param :attach_stdout, :bool
58
58
  param :attach_stdin, :bool
59
59
  param :attach_stderr, :bool
60
- param :capsule_id, :identifier, :desc => N_('The capsule this container will have to use
61
- to get the image. Relevant for images
62
- retrieved from katello registry.')
60
+ param :capsule_id, :identifier, :desc => N_('The capsule this container will have to ' +
61
+ 'use to get the image. Relevant for images ' +
62
+ 'retrieved from katello registry.')
63
63
  end
64
64
  end
65
65
 
66
66
  api :POST, '/containers/', N_('Create a container')
67
67
  api :POST, '/compute_resources/:compute_resource_id/containers/',
68
- N_('Create container in a compute resource')
68
+ N_('Create container on a compute resource')
69
69
  param_group :container, :as => :create
70
70
 
71
71
  def create
@@ -87,17 +87,25 @@ module Api
87
87
 
88
88
  api :DELETE, '/containers/:id/', N_('Delete a container')
89
89
  api :DELETE, '/compute_resources/:compute_resource_id/containers/:id',
90
- N_('Delete container in a compute resource')
90
+ N_('Delete container on a compute resource')
91
91
  param :id, :identifier, :required => true
92
92
  param :compute_resource_id, :identifier
93
93
 
94
94
  def destroy
95
- process_response @container.destroy
95
+ deleted_identifier = ForemanDocker::ContainerRemover.remove_unmanaged(
96
+ @container.compute_resource_id,
97
+ @container.uuid)
98
+
99
+ if deleted_identifier
100
+ process_response @container.destroy
101
+ else
102
+ render :json => { :error => 'Could not delete container on Docker host' }, :status => :precondition_failed
103
+ end
96
104
  end
97
105
 
98
106
  api :GET, '/containers/:id/logs', N_('Show container logs')
99
107
  api :GET, '/compute_resources/:compute_resource_id/containers/:id/logs',
100
- N_('Show logs from a container in a compute resource')
108
+ N_('Show logs from a container on a compute resource')
101
109
  param :id, :identifier, :required => true
102
110
  param :compute_resource_id, :identifier
103
111
  param :stdout, :bool
@@ -113,7 +121,7 @@ module Api
113
121
 
114
122
  api :PUT, '/containers/:id/power', N_('Run power operation on a container')
115
123
  api :PUT, '/compute_resources/:compute_resource_id/containers/:id/power',
116
- N_('Run power operation on a container in a compute resource')
124
+ N_('Run power operation on a container on a compute resource')
117
125
  param :id, :identifier, :required => true
118
126
  param :compute_resource_id, :identifier
119
127
  param :power_action, String,
@@ -58,9 +58,9 @@ module Containers
58
58
  else
59
59
  @docker_container_wizard_states_environment = @state.environment
60
60
  process_error(
61
- :error_msg => service.errors.full_messages.join(','),
62
- :object => @state.environment,
63
- :render => 'environment')
61
+ :redirect => containers_path,
62
+ :error_msg => service.full_messages.join(','),
63
+ :object => @state.environment)
64
64
  end
65
65
  end
66
66
  end
@@ -20,12 +20,17 @@ class ContainersController < ::ApplicationController
20
20
  end
21
21
 
22
22
  def destroy
23
- if container_deletion
23
+ if (deleted_identifier = container_deletion)
24
24
  process_success(:success_redirect => containers_path,
25
25
  :success_msg => (_("Container %s is being deleted.") %
26
- @deleted_identifier))
26
+ deleted_identifier))
27
27
  else
28
- process_error(:redirect => containers_path)
28
+ error(_('Your container could not be deleted in Docker'))
29
+ if @container.present?
30
+ process_error(:redirect => containers_path)
31
+ else
32
+ redirect_to :back
33
+ end
29
34
  end
30
35
  rescue ActiveRecord::RecordNotFound
31
36
  not_found
@@ -94,25 +99,18 @@ class ContainersController < ::ApplicationController
94
99
  end
95
100
 
96
101
  def container_deletion
97
- # Unmanaged container - only present in Compute Resource
98
102
  if params[:compute_resource_id].present?
99
- @deleted_identifier = params[:id]
100
- destroy_compute_resource_vm(params[:compute_resource_id], params[:id])
101
- else # Managed container
103
+ compute_resource_id = params[:compute_resource_id]
104
+ container_uuid = params[:id]
105
+ else
102
106
  find_container
103
- @deleted_identifier = @container.name
104
-
105
- destroy_compute_resource_vm(@container.compute_resource, @container.uuid) &&
106
- @container.destroy
107
+ compute_resource_id = @container.compute_resource_id
108
+ container_uuid = @container.uuid
107
109
  end
108
- end
109
110
 
110
- def destroy_compute_resource_vm(resource_id, uuid)
111
- @container_resource = ComputeResource.authorized(:destroy_compute_resources_vms)
112
- .find(resource_id)
113
- @container_resource.destroy_vm(uuid)
114
- rescue => error
115
- logger.error "#{error.message} (#{error.class})\n#{error.backtrace.join("\n")}"
116
- false
111
+ deleted_identifier = ForemanDocker::ContainerRemover.remove_unmanaged(
112
+ compute_resource_id, container_uuid)
113
+ @container.destroy if @container.present?
114
+ deleted_identifier
117
115
  end
118
116
  end
@@ -2,7 +2,7 @@ module ContainerStepsHelper
2
2
  def container_wizard(step)
3
3
  wizard_header(
4
4
  step,
5
- *wizard_steps.map { |s| s.to_s.humanize }
5
+ *humanized_steps
6
6
  )
7
7
  end
8
8
 
@@ -18,6 +18,10 @@ module ContainerStepsHelper
18
18
  end
19
19
  end
20
20
 
21
+ def humanized_steps
22
+ [_('Preliminary'), _('Image'), _('Configuration'), _('Environment')]
23
+ end
24
+
21
25
  def last_step?
22
26
  step == wizard_steps.last
23
27
  end
@@ -31,7 +31,9 @@ module ContainersHelper
31
31
  @compute_resource = container.compute_resource
32
32
  title_actions(
33
33
  button_group(
34
- link_to(_('Commit'), '#commit-modal', :'data-toggle' => 'modal')
34
+ link_to(_('Commit'), '#commit-modal',
35
+ :'data-toggle' => 'modal',
36
+ :class => 'btn btn-default')
35
37
  ),
36
38
  button_group(container_power_action(container.in_fog)),
37
39
  button_group(
@@ -40,7 +42,8 @@ module ContainersHelper
40
42
  .merge(:auth_object => container,
41
43
  :auth_action => 'destroy',
42
44
  :authorizer => authorizer),
43
- :confirm => _("Delete %s?") % container.name)
45
+ :confirm => _("Delete %s?") % container.name,
46
+ :class => 'btn btn-default')
44
47
  )
45
48
  )
46
49
  end
@@ -72,11 +75,6 @@ module ContainersHelper
72
75
  :vm => vm }
73
76
  end
74
77
 
75
- def auto_complete_docker_search(name, val, options = {})
76
- addClass options, 'form-control'
77
- text_field_tag(name, val, options)
78
- end
79
-
80
78
  def processes(container)
81
79
  ForemanDocker::Docker.get_container(container).top
82
80
  end
@@ -36,7 +36,7 @@ module FogExtensions
36
36
  end
37
37
 
38
38
  def vm_description
39
- _('%{cores} Cores and %{memory} memory') %
39
+ _('%{cores} cores and %{memory} memory') %
40
40
  { :cores => cpus, :memory => number_to_human_size(memory.to_i) }
41
41
  end
42
42
  end
@@ -3,16 +3,17 @@ class DockerRegistry < ActiveRecord::Base
3
3
  include Taxonomix
4
4
  include Encryptable
5
5
 
6
- attr_accessible :name, :url, :username, :password, :locations, :organizations
7
-
8
6
  has_many :containers, :foreign_key => "registry_id", :dependent => :destroy
9
7
  encrypts :password
10
8
 
11
- attr_accessible :name, :url, :username, :password, :locations, :organizations
9
+ attr_accessible :name, :url, :username, :password, :locations, :organizations,
10
+ :description
12
11
 
13
12
  validates_lengths_from_database
14
13
  validates :name, :presence => true, :uniqueness => true
15
- validates :url, :presence => true, :uniqueness => true
14
+ validates :url, :presence => true, :uniqueness => true,
15
+ :url_schema => ['http', 'https']
16
+ validate :attempt_login
16
17
 
17
18
  scoped_search :on => :name, :complete_value => true
18
19
  scoped_search :on => :url
@@ -37,4 +38,15 @@ class DockerRegistry < ActiveRecord::Base
37
38
  def self.humanize_class_name(_name = nil)
38
39
  _("Docker/Registry")
39
40
  end
41
+
42
+ private
43
+
44
+ def attempt_login
45
+ login_endpoint = RestClient::Resource.new(url + '/v1/users',
46
+ :user => username,
47
+ :password => password)
48
+ login_endpoint.get == "\"OK\""
49
+ rescue => e
50
+ errors.add(:base, _('Unable to log in to this Docker Registry - %s') % e)
51
+ end
40
52
  end
@@ -5,6 +5,7 @@ module ForemanDocker
5
5
  attr_accessible :email
6
6
 
7
7
  validates :url, :format => { :with => URI.regexp }
8
+ validates :email, :format => { :with => /.+@.+\..+/i }, :allow_blank => true
8
9
 
9
10
  def self.model_name
10
11
  ComputeResource.model_name
@@ -16,7 +17,7 @@ module ForemanDocker
16
17
  end
17
18
 
18
19
  def capabilities
19
- [:image]
20
+ []
20
21
  end
21
22
 
22
23
  def supports_update?
@@ -93,7 +93,7 @@ module Service
93
93
  end
94
94
 
95
95
  def full_messages
96
- @errors.respond_to?(:full_messages) ? @errors.full_messages : @errors
96
+ errors.respond_to?(:full_messages) ? errors.full_messages : errors
97
97
  end
98
98
 
99
99
  def run_container(container)
@@ -0,0 +1,14 @@
1
+ Deface::Override.new(
2
+ :virtual_path => 'compute_profiles/show',
3
+ :name => 'remove_docker_from_compute_profiles',
4
+ :replace => "erb[silent]:contains('ComputeResource.authorized(:view_compute_resources)')",
5
+ :text => "<% ComputeResource.where.not(:type => 'ForemanDocker::Docker').
6
+ authorized(:view_compute_resources).each do |compute_resource| %>"
7
+ )
8
+
9
+ Deface::Override.new(
10
+ :virtual_path => 'compute_resources/show',
11
+ :name => 'remove_compute_profiles_tab',
12
+ :replace => 'a[href="#compute_profiles"]',
13
+ :text => "<%= link_to(_('Compute profiles'), '#compute_profiles', :'data-toggle' => 'tab') unless @compute_resource.type == 'ForemanDocker::Docker' %>"
14
+ )
@@ -0,0 +1,10 @@
1
+ Deface::Override.new(
2
+ :virtual_path => 'compute_resources/show',
3
+ :name => 'rename_virtual_machines_containers',
4
+ :replace => "erb[loud]:contains('Virtual Machines')",
5
+ :text => "<%= if @compute_resource.type == 'ForemanDocker::Docker'
6
+ _('Containers')
7
+ else
8
+ _('Virtual Machines')
9
+ end %>"
10
+ )
@@ -0,0 +1,20 @@
1
+ module ForemanDocker
2
+ module ContainerRemover
3
+ module_function
4
+
5
+ def remove_unmanaged(compute_resource_id, uuid)
6
+ deleted_identifier = uuid
7
+
8
+ ComputeResource.
9
+ authorized(:destroy_compute_resources_vms).
10
+ find(compute_resource_id).
11
+ destroy_vm(uuid)
12
+
13
+ deleted_identifier
14
+ rescue => error
15
+ Rails.logger.
16
+ error "#{error.message} (#{error.class})\n#{error.backtrace.join("\n")}"
17
+ false
18
+ end
19
+ end
20
+ end
@@ -1,16 +1,13 @@
1
1
  <% title _("Containers") %>
2
2
 
3
- <% if authorized? %>
4
- <% title_actions button_group(link_to_if_authorized _("New container"), hash_for_new_container_path,
5
- :class => 'btn-success') %>
6
- <% end %>
3
+ <%= title_actions(new_link(_("New container"))) %>
7
4
 
8
5
  <ul class="nav nav-tabs" data-tabs="tabs">
9
6
  <% @container_resources.each_with_index do |resource, i| %>
10
7
  <% if i == 0 %>
11
- <li class="active"><a href="#<%= "primary" %>" data-toggle="tab"><%= _("#{resource.name}") %></a></li>
8
+ <li class="active"><a href="#<%= "primary" %>" data-toggle="tab"><%= resource.name %></a></li>
12
9
  <% else %>
13
- <li><a href="#<%= resource.id %>" data-toggle="tab"><%= _("#{resource.name}") %></a></li>
10
+ <li><a href="#<%= resource.id %>" data-toggle="tab"><%= resource.name %></a></li>
14
11
  <% end %>
15
12
  <% end %>
16
13
  </ul>
@@ -33,4 +30,4 @@
33
30
  </div>
34
31
  <% end %>
35
32
  </div>
36
- </div>
33
+ </div>