katello 3.4.0.rc2 → 3.4.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of katello might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/app/controllers/katello/api/rhsm/candlepin_dynflow_proxy_controller.rb +43 -0
- data/app/controllers/katello/api/rhsm/candlepin_proxies_controller.rb +20 -14
- data/app/controllers/katello/api/v2/content_views_controller.rb +2 -2
- data/app/controllers/katello/api/v2/errata_controller.rb +1 -0
- data/app/controllers/katello/api/v2/packages_controller.rb +6 -2
- data/app/lib/actions/candlepin/async_hypervisors.rb +22 -0
- data/app/lib/actions/candlepin/import_pool_handler.rb +19 -23
- data/app/lib/actions/katello/capsule_content/sync.rb +1 -0
- data/app/lib/actions/katello/host/hypervisors.rb +16 -4
- data/app/lib/actions/katello/host/hypervisors_update.rb +2 -2
- data/app/lib/actions/katello/host/upload_package_profile.rb +13 -6
- data/app/lib/actions/katello/repository/remove_content.rb +8 -8
- data/app/lib/actions/middleware/backend_services_check.rb +2 -2
- data/app/lib/katello/capsule_content.rb +6 -0
- data/app/lib/katello/resources/candlepin.rb +12 -7
- data/app/models/katello/concerns/organization_extensions.rb +4 -0
- data/app/models/katello/events/import_pool.rb +17 -0
- data/app/models/katello/glue/candlepin/owner.rb +4 -0
- data/app/models/katello/host/subscription_facet.rb +9 -2
- data/app/models/katello/ping.rb +4 -4
- data/app/models/katello/subscription_status.rb +5 -2
- data/app/services/cert/certs.rb +7 -0
- data/config/routes/api/rhsm.rb +4 -2
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/views/activation-key-details.html +2 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/views/activation-key-host-collections-table.html +4 -6
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/details/views/activation-key-info.html +2 -2
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/activation-keys/new/views/activation-key-new.html +1 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-details.html +1 -0
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-hosts/details/views/content-host-info.html +1 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/details/filters/views/filter-repositories.html +0 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/content-views/new/views/content-view-new.html +1 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/docker-tags/details/views/docker-tag-environments.html +4 -11
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/gpg-keys/new/views/new-gpg-key.html +1 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/host-collections/new/views/new-host-collection.html +1 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/repositories/new/views/new-repository.html +1 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/views/product-details.html +1 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/new/new-sync-plan-modal.controller.js +46 -0
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/new/product-form.controller.js +15 -2
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/new/views/new-sync-plan-modal.html +18 -0
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/new/views/product-new-form.html +40 -38
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/products.routes.js +0 -19
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/subscriptions/content-access-mode-banner.directive.js +22 -0
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/subscriptions/details/views/subscription-details.html +2 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/subscriptions/manifest/views/manifest-import.html +1 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/subscriptions/manifest/views/manifest.html +2 -0
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/subscriptions/views/content-access-mode-banner.html +5 -0
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/sync-plans/details/views/sync-plan-info.html +0 -3
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/sync-plans/new/new-sync-plan.controller.js +16 -24
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/sync-plans/new/views/new-sync-plan-form.html +52 -48
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/sync-plans/new/views/new-sync-plan.html +3 -1
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/sync-plans/sync-plan-helper.service.js +66 -0
- data/lib/katello/engine.rb +10 -0
- data/lib/katello/params_parser_wrapper.rb +16 -0
- data/lib/katello/permissions/host_permissions.rb +7 -3
- data/lib/katello/plugin.rb +4 -4
- data/lib/katello/tasks/regenerate_ueber_certs.rake +1 -1
- data/lib/katello/tasks/repository.rake +23 -0
- data/lib/katello/version.rb +1 -1
- metadata +13 -5
- data/engines/bastion_katello/app/assets/javascripts/bastion_katello/products/details/views/product-new-sync-plan.html +0 -2
@@ -0,0 +1,17 @@
|
|
1
|
+
module Katello
|
2
|
+
module Events
|
3
|
+
class ImportPool
|
4
|
+
EVENT_TYPE = 'import_pool'.freeze
|
5
|
+
|
6
|
+
def initialize(pool_id)
|
7
|
+
@pool = ::Katello::Pool.find_by(:id => pool_id)
|
8
|
+
end
|
9
|
+
|
10
|
+
def run
|
11
|
+
@pool.try(:import_data)
|
12
|
+
rescue RestClient::ResourceNotFound
|
13
|
+
Rails.logger.warn "skipped re-index of non-existent pool #{@pool.cp_id}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -34,6 +34,10 @@ module Katello
|
|
34
34
|
Resources::Candlepin::Owner.update(self.label, :defaultServiceLevel => level)
|
35
35
|
end
|
36
36
|
|
37
|
+
def content_access_mode
|
38
|
+
self.owner_details['contentAccessMode']
|
39
|
+
end
|
40
|
+
|
37
41
|
def pools(consumer_uuid = nil)
|
38
42
|
if consumer_uuid
|
39
43
|
Resources::Candlepin::Owner.pools self.label, :consumer => consumer_uuid
|
@@ -106,8 +106,15 @@ module Katello
|
|
106
106
|
end
|
107
107
|
end
|
108
108
|
|
109
|
-
def update_subscription_status
|
110
|
-
host.get_status(::Katello::SubscriptionStatus)
|
109
|
+
def update_subscription_status(status_override = nil)
|
110
|
+
status = host.get_status(::Katello::SubscriptionStatus)
|
111
|
+
if status_override
|
112
|
+
status.status = status.to_status(:status_override => status_override)
|
113
|
+
status.save!
|
114
|
+
else
|
115
|
+
host.get_status(::Katello::SubscriptionStatus).refresh!
|
116
|
+
end
|
117
|
+
|
111
118
|
host.refresh_global_status!
|
112
119
|
end
|
113
120
|
|
data/app/models/katello/ping.rb
CHANGED
@@ -115,19 +115,19 @@ module Katello
|
|
115
115
|
def pulp_without_auth(url)
|
116
116
|
body = backend_status(url, :pulp)
|
117
117
|
|
118
|
-
fail _("Pulp does not appear to be running.") if body.empty?
|
118
|
+
fail _("Pulp does not appear to be running at %s.") % url if body.empty?
|
119
119
|
json = JSON.parse(body)
|
120
120
|
|
121
121
|
if json['database_connection'] && json['database_connection']['connected'] != true
|
122
|
-
fail _("Pulp database connection issue.")
|
122
|
+
fail _("Pulp database connection issue at %s.") % url
|
123
123
|
end
|
124
124
|
|
125
125
|
if json['messaging_connection'] && json['messaging_connection']['connected'] != true
|
126
|
-
fail _("Pulp message bus connection issue.")
|
126
|
+
fail _("Pulp message bus connection issue at %s.") % url
|
127
127
|
end
|
128
128
|
|
129
129
|
unless all_pulp_workers_present?(json)
|
130
|
-
fail _("Not all necessary pulp workers running.")
|
130
|
+
fail _("Not all necessary pulp workers running at %s.") % url
|
131
131
|
end
|
132
132
|
|
133
133
|
json
|
@@ -35,9 +35,12 @@ module Katello
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
def to_status(
|
38
|
+
def to_status(options = {})
|
39
39
|
return UNKNOWN unless host.subscription_facet.try(:uuid)
|
40
|
-
|
40
|
+
status_override = options.fetch(:status_override, nil)
|
41
|
+
status = status_override || Katello::Candlepin::Consumer.new(host.subscription_facet.uuid, host.organization.label).entitlement_status
|
42
|
+
|
43
|
+
case status
|
41
44
|
when Katello::Candlepin::Consumer::ENTITLEMENTS_VALID
|
42
45
|
VALID
|
43
46
|
when Katello::Candlepin::Consumer::ENTITLEMENTS_PARTIAL
|
data/app/services/cert/certs.rb
CHANGED
@@ -15,5 +15,12 @@ module Cert
|
|
15
15
|
def self.ssl_client_key
|
16
16
|
@ssl_client_key ||= OpenSSL::PKey::RSA.new(File.open(Setting['pulp_client_key'], 'r').read)
|
17
17
|
end
|
18
|
+
|
19
|
+
def self.verify_ueber_cert(organization)
|
20
|
+
ueber_cert = OpenSSL::X509::Certificate.new(self.ueber_cert(organization)[:cert])
|
21
|
+
cert_store = OpenSSL::X509::Store.new
|
22
|
+
cert_store.add_file Setting[:ssl_ca_file]
|
23
|
+
organization.regenerate_ueber_cert unless cert_store.verify ueber_cert
|
24
|
+
end
|
18
25
|
end
|
19
26
|
end
|
data/config/routes/api/rhsm.rb
CHANGED
@@ -16,6 +16,7 @@ Katello::Engine.routes.draw do
|
|
16
16
|
end
|
17
17
|
match '/consumers' => 'candlepin_proxies#consumer_create', :via => :post
|
18
18
|
match '/hypervisors' => 'candlepin_proxies#hypervisors_update', :via => :post
|
19
|
+
match '/hypervisors/:owner/' => 'candlepin_proxies#async_hypervisors_update', :via => :post
|
19
20
|
match '/owners/:organization_id/environments' => 'candlepin_proxies#rhsm_index', :via => :get
|
20
21
|
match '/owners/:organization_id/pools' => 'candlepin_proxies#get', :via => :get, :as => :proxy_owner_pools_path
|
21
22
|
match '/owners/:organization_id/servicelevels' => 'candlepin_proxies#get', :via => :get, :as => :proxy_owner_servicelevels_path
|
@@ -39,8 +40,8 @@ Katello::Engine.routes.draw do
|
|
39
40
|
match '/deleted_consumers' => 'candlepin_proxies#get', :via => :get, :as => :proxy_deleted_consumers_path
|
40
41
|
match '/entitlements/:id' => 'candlepin_proxies#get', :via => :get, :as => :proxy_entitlements_path
|
41
42
|
match '/subscriptions' => 'candlepin_proxies#post', :via => :post, :as => :proxy_subscriptions_post_path
|
42
|
-
match '/consumers/:id/profile/' => '
|
43
|
-
match '/consumers/:id/packages/' => '
|
43
|
+
match '/consumers/:id/profile/' => 'candlepin_dynflow_proxy#upload_package_profile', :via => :put
|
44
|
+
match '/consumers/:id/packages/' => 'candlepin_dynflow_proxy#upload_package_profile', :via => :put
|
44
45
|
match '/consumers/:id/tracer/' => 'candlepin_proxies#upload_tracer_profile', :via => :put
|
45
46
|
match '/consumers/:id/checkin/' => 'candlepin_proxies#checkin', :via => :put
|
46
47
|
match '/consumers/:id' => 'candlepin_proxies#facts', :via => :put
|
@@ -54,6 +55,7 @@ Katello::Engine.routes.draw do
|
|
54
55
|
match '/consumers/:id/content_overrides/' => 'candlepin_proxies#delete', :via => :delete, :as => :proxy_consumer_content_overrides_delete_path
|
55
56
|
match '/consumers/:id/available_releases' => 'candlepin_proxies#available_releases', :via => :get
|
56
57
|
match '/systems/:id/enabled_repos' => 'candlepin_proxies#enabled_repos', :via => :put
|
58
|
+
match '/jobs/:jobId' => 'candlepin_proxies#get', :via => :get, :as => :proxy_jobs_get_path
|
57
59
|
match '/status' => 'candlepin_proxies#server_status', :via => :get
|
58
60
|
end
|
59
61
|
end
|
@@ -40,6 +40,7 @@
|
|
40
40
|
</div>
|
41
41
|
|
42
42
|
<nav data-block="navigation">
|
43
|
+
<div content-access-mode-banner></div>
|
43
44
|
<ul class="nav nav-tabs details-nav">
|
44
45
|
<li ng-class="{active: isState('activation-key.info')}">
|
45
46
|
<a ui-sref="activation-key.info">
|
@@ -89,4 +90,4 @@
|
|
89
90
|
<section data-block="content">
|
90
91
|
<div ui-view></div>
|
91
92
|
</section>
|
92
|
-
</div>
|
93
|
+
</div>
|
@@ -3,12 +3,10 @@
|
|
3
3
|
|
4
4
|
<div data-extend-template="layouts/partials/table.html">
|
5
5
|
<div data-block="search">
|
6
|
-
<
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
ng-model="hostCollectionFilter"/>
|
11
|
-
</div>
|
6
|
+
<input type="text"
|
7
|
+
class="form-control"
|
8
|
+
placeholder="{{ 'Filter' | translate }}"
|
9
|
+
ng-model="hostCollectionFilter"/>
|
12
10
|
</div>
|
13
11
|
|
14
12
|
<div data-block="list-actions">
|
@@ -1,9 +1,9 @@
|
|
1
1
|
<span page-title ng-model="activationKey">{{ 'Details for Activation Key:' | translate }} {{ activationKey.name }}</span>
|
2
2
|
|
3
3
|
<div bst-alert="info">
|
4
|
-
<
|
4
|
+
<span translate>
|
5
5
|
This activation key may be used during system registration. For example:
|
6
|
-
</
|
6
|
+
</span>
|
7
7
|
<p translate>
|
8
8
|
subscription-manager register --org="{{ activationKey.organization.label }}" --activationkey="{{ activationKey.name }}"
|
9
9
|
</p>
|
@@ -55,7 +55,6 @@
|
|
55
55
|
ng-class="{'table-mask': table.working}">
|
56
56
|
<thead>
|
57
57
|
<tr bst-table-head row-select>
|
58
|
-
<th bst-table-column="affectedRepos">Affected?</th>
|
59
58
|
<th bst-table-column="name" translate>Name</th>
|
60
59
|
<th bst-table-column="product" translate>Product</th>
|
61
60
|
<th bst-table-column="type" translate>Type</th>
|
@@ -1,17 +1,10 @@
|
|
1
1
|
|
2
2
|
<div data-extend-template="layouts/partials/table.html">
|
3
3
|
<div data-block="search">
|
4
|
-
<
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
class="form-control"
|
9
|
-
placeholder="{{ 'Filter' | translate }}"
|
10
|
-
ng-model="dockerTagFilter"/>
|
11
|
-
|
12
|
-
</div>
|
13
|
-
</form>
|
14
|
-
</div>
|
4
|
+
<input type="text"
|
5
|
+
class="form-control"
|
6
|
+
placeholder="{{ 'Filter' | translate }}"
|
7
|
+
ng-model="dockerTagFilter"/>
|
15
8
|
</div>
|
16
9
|
|
17
10
|
<span data-block="no-rows-message" translate>
|
@@ -5,7 +5,7 @@
|
|
5
5
|
<h2 translate>Create Host Collection</h2>
|
6
6
|
</header>
|
7
7
|
|
8
|
-
<div data-block="content">
|
8
|
+
<div data-block="content" class="row">
|
9
9
|
<form name="hostCollectionForm" class="col-sm-5" novalidate role="form">
|
10
10
|
<div bst-form-group label="{{ 'Name' | translate }}">
|
11
11
|
<input id="name"
|
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
<div bst-alerts error-messages="errorMessages" success-messages="successMessages"></div>
|
6
6
|
|
7
|
-
<div data-block="content">
|
7
|
+
<div data-block="content" class="row">
|
8
8
|
<form name="repositoryForm" class="col-sm-5" novalidate role="form">
|
9
9
|
<div>
|
10
10
|
<h4 translate> General Information </h4>
|
@@ -0,0 +1,46 @@
|
|
1
|
+
/**
|
2
|
+
* @ngdoc object
|
3
|
+
* @name Bastion.proudcts.controller:NewSyncPlanModalController
|
4
|
+
*
|
5
|
+
* @requires $scope
|
6
|
+
* @requires $uibModalInstance
|
7
|
+
* @requires SyncPlan
|
8
|
+
* @requires SyncPlanHelper
|
9
|
+
*
|
10
|
+
* @description
|
11
|
+
* A controller for creating a new sync plan in a modal.
|
12
|
+
*/
|
13
|
+
angular.module('Bastion.products').controller('NewSyncPlanModalController',
|
14
|
+
['$scope', '$uibModalInstance', 'SyncPlan', 'SyncPlanHelper',
|
15
|
+
function ($scope, $uibModalInstance, SyncPlan, SyncPlanHelper) {
|
16
|
+
function success(syncPlan) {
|
17
|
+
$uibModalInstance.close(syncPlan);
|
18
|
+
}
|
19
|
+
|
20
|
+
function error(response) {
|
21
|
+
var form = SyncPlanHelper.getForm();
|
22
|
+
|
23
|
+
angular.forEach(response.data.errors, function (errors, field) {
|
24
|
+
form[field].$setValidity('server', false);
|
25
|
+
form[field].$error.messages = errors;
|
26
|
+
});
|
27
|
+
}
|
28
|
+
|
29
|
+
$scope.ok = function (syncPlan) {
|
30
|
+
SyncPlanHelper.createSyncPlan(syncPlan, success, error);
|
31
|
+
};
|
32
|
+
|
33
|
+
$scope.cancel = function () {
|
34
|
+
$uibModalInstance.dismiss('cancel');
|
35
|
+
};
|
36
|
+
|
37
|
+
$scope.isFormDisabled = function () {
|
38
|
+
var form = SyncPlanHelper.getForm();
|
39
|
+
return form && !form.$valid;
|
40
|
+
};
|
41
|
+
|
42
|
+
$scope.intervals = SyncPlanHelper.getIntervals();
|
43
|
+
$scope.syncPlan = new SyncPlan();
|
44
|
+
$scope.syncPlan.interval = $scope.intervals[0].id;
|
45
|
+
}]
|
46
|
+
);
|
@@ -4,19 +4,21 @@
|
|
4
4
|
*
|
5
5
|
* @requires $scope
|
6
6
|
* @requires $q
|
7
|
+
* @requires $uibModal
|
7
8
|
* @requires Product
|
8
9
|
* @requires GPGKey
|
9
10
|
* @requires SyncPlan
|
10
11
|
* @requires FormUtils
|
11
12
|
*
|
13
|
+
*
|
12
14
|
* @description
|
13
15
|
* Provides the functionality specific to Products for use with the Nutupane UI pattern.
|
14
16
|
* Defines the columns to display and the transform function for how to generate each row
|
15
17
|
* within the table.
|
16
18
|
*/
|
17
19
|
angular.module('Bastion.products').controller('ProductFormController',
|
18
|
-
['$scope', '$q', 'Product', 'GPGKey', 'SyncPlan', 'FormUtils', 'GlobalNotification',
|
19
|
-
function ($scope, $q, Product, GPGKey, SyncPlan, FormUtils, GlobalNotification) {
|
20
|
+
['$scope', '$q', '$uibModal', 'Product', 'GPGKey', 'SyncPlan', 'FormUtils', 'GlobalNotification',
|
21
|
+
function ($scope, $q, $uibModal, Product, GPGKey, SyncPlan, FormUtils, GlobalNotification) {
|
20
22
|
|
21
23
|
function fetchGpgKeys() {
|
22
24
|
return GPGKey.queryUnpaged(function (gpgKeys) {
|
@@ -62,5 +64,16 @@ angular.module('Bastion.products').controller('ProductFormController',
|
|
62
64
|
$q.all([fetchSyncPlans().$promise, fetchGpgKeys().$promise]).finally(function () {
|
63
65
|
$scope.page.loading = false;
|
64
66
|
});
|
67
|
+
|
68
|
+
$scope.openSyncPlanModal = function () {
|
69
|
+
$uibModal.open({
|
70
|
+
templateUrl: 'products/new/views/new-sync-plan-modal.html',
|
71
|
+
controller: 'NewSyncPlanModalController'
|
72
|
+
}).result.then(function ($value) {
|
73
|
+
fetchSyncPlans().$promise.then(function () {
|
74
|
+
$scope.product['sync_plan_id'] = $value.id;
|
75
|
+
});
|
76
|
+
});
|
77
|
+
};
|
65
78
|
}]
|
66
79
|
);
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<div data-extend-template="components/views/bst-modal.html" ng-controller="NewSyncPlanController">
|
2
|
+
<h4 data-block="modal-header" translate>
|
3
|
+
New Sync Plan
|
4
|
+
</h4>
|
5
|
+
|
6
|
+
<div data-block="modal-body">
|
7
|
+
<div ng-include="'sync-plans/new/views/new-sync-plan-form.html'"></div>
|
8
|
+
</div>
|
9
|
+
|
10
|
+
<span data-block="modal-confirm-button">
|
11
|
+
<button class="btn btn-primary" ng-click="ok(syncPlan)"
|
12
|
+
ng-disabled="isFormDisabled()">
|
13
|
+
<span translate>Save</span>
|
14
|
+
</button>
|
15
|
+
</span>
|
16
|
+
</div>
|
17
|
+
|
18
|
+
|
@@ -1,30 +1,31 @@
|
|
1
|
-
<
|
1
|
+
<div class="row">
|
2
|
+
<form name="productForm" class="col-sm-5" novalidate role="form">
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
4
|
+
<div bst-form-group label="{{ 'Name' | translate }}">
|
5
|
+
<input id="name"
|
6
|
+
name="name"
|
7
|
+
ng-model="product.name"
|
8
|
+
type="text"
|
9
|
+
autofocus
|
10
|
+
required/>
|
11
|
+
</div>
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
13
|
+
<div bst-form-group label="{{ 'Label' | translate }}">
|
14
|
+
<input id="label"
|
15
|
+
name="label"
|
16
|
+
ng-model="product.label"
|
17
|
+
type="text"
|
18
|
+
required/>
|
19
|
+
</div>
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
21
|
+
<div bst-form-group label="{{ 'GPG Key' | translate }}">
|
22
|
+
<select id="gpg_key_id"
|
23
|
+
name="gpg_key_id"
|
24
|
+
ng-model="product.gpg_key_id"
|
25
|
+
ng-options="gpg_key.id as gpg_key.name for gpg_key in gpgKeys">
|
26
|
+
<option value=""></option>
|
27
|
+
</select>
|
28
|
+
</div>
|
28
29
|
|
29
30
|
<div bst-form-group label="{{ 'Sync Plan' | translate }}">
|
30
31
|
<select id="sync_plan_id"
|
@@ -33,23 +34,24 @@
|
|
33
34
|
ng-options="syncPlan.id as syncPlan.name for syncPlan in syncPlans">
|
34
35
|
<option value=""></option>
|
35
36
|
</select>
|
36
|
-
<a
|
37
|
+
<a ng-click="openSyncPlanModal()">
|
37
38
|
<i class="pficon pficon-add-circle-o"></i>
|
38
|
-
Create Sync Plan
|
39
|
+
<span translate>Create Sync Plan</span>
|
39
40
|
</a>
|
40
41
|
</div>
|
41
42
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
43
|
+
<div bst-form-group label="{{ 'Description' | translate }}">
|
44
|
+
<textarea id="description"
|
45
|
+
name="description"
|
46
|
+
ng-model="product.description">
|
47
|
+
</textarea>
|
48
|
+
</div>
|
48
49
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
50
|
+
<div bst-form-buttons
|
51
|
+
on-cancel="transitionTo('products')"
|
52
|
+
on-save="save(product)"
|
53
|
+
working="working">
|
54
|
+
</div>
|
54
55
|
|
55
|
-
</form>
|
56
|
+
</form>
|
57
|
+
</div>
|