foreman_docker 2.0.1 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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>