mirror of https://github.com/rancher/ui.git
Merge pull request #145 from vincent99/service-balancer
Load Balancer Service
This commit is contained in:
commit
b7e4a28e64
|
|
@ -7,6 +7,6 @@ export default Ember.Component.extend({
|
||||||
tagName: 'nav',
|
tagName: 'nav',
|
||||||
hasServices: function() {
|
hasServices: function() {
|
||||||
var store = this.get('store');
|
var store = this.get('store');
|
||||||
return store && store.hasRecordFor('schema','service') && this.get('session.showServices');
|
return store && store.hasRecordFor('schema','service');
|
||||||
}.property(),
|
}.property(),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,14 @@ var EnvironmentController = Cattle.TransitioningResourceController.extend({
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
addBalancer: function() {
|
||||||
|
this.transitionToRoute('service.new-balancer', {
|
||||||
|
queryParams: {
|
||||||
|
environmentId: this.get('id'),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
edit: function() {
|
edit: function() {
|
||||||
this.transitionToRoute('environment.edit', this.get('id'));
|
this.transitionToRoute('environment.edit', this.get('id'));
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -6,5 +6,8 @@ export default Ember.ObjectController.extend({
|
||||||
addService: function() {
|
addService: function() {
|
||||||
this.get('controllers.environment').send('addService');
|
this.get('controllers.environment').send('addService');
|
||||||
},
|
},
|
||||||
|
addBalancer: function() {
|
||||||
|
this.get('controllers.environment').send('addBalancer');
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,12 @@
|
||||||
<div class="pod-column">
|
<div class="pod-column">
|
||||||
{{#each item in col}}
|
{{#each item in col}}
|
||||||
{{#if item.isNewPlaceHolder}}
|
{{#if item.isNewPlaceHolder}}
|
||||||
{{add-pod action="addService" label="Add Service"}}
|
{{#if item.isService}}
|
||||||
|
{{add-pod action="addService" label="Add Service"}}
|
||||||
|
{{/if}}
|
||||||
|
{{#if item.isBalancer}}
|
||||||
|
{{add-pod action="addBalancer" label="Add Load Balancer"}}
|
||||||
|
{{/if}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{#with item as service controller="service"}}
|
{{#with item as service controller="service"}}
|
||||||
{{service-pod model=service}}
|
{{service-pod model=service}}
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,9 @@ export default ColumnView.extend({
|
||||||
columns[nextIndex()].push(services.objectAt(i));
|
columns[nextIndex()].push(services.objectAt(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a placeholder for where to put the 'Add Service' button
|
// Add a placeholder for where to put the 'Add Service' and 'Add Balancer' buttons
|
||||||
columns[nextIndex()].push(Ember.Object.create({isNewPlaceHolder: true}));
|
columns[nextIndex()].push(Ember.Object.create({isNewPlaceHolder: true, isService: true}));
|
||||||
|
columns[nextIndex()].push(Ember.Object.create({isNewPlaceHolder: true, isBalancer: true}));
|
||||||
|
|
||||||
this.set('podCount', podCount);
|
this.set('podCount', podCount);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,59 @@
|
||||||
|
import Cattle from 'ui/utils/cattle';
|
||||||
|
|
||||||
|
var LoadBalancerServiceController = Cattle.TransitioningResourceController.extend({
|
||||||
|
actions: {
|
||||||
|
activate: function() {
|
||||||
|
return this.doAction('activate');
|
||||||
|
},
|
||||||
|
|
||||||
|
deactivate: function() {
|
||||||
|
return this.doAction('deactivate');
|
||||||
|
},
|
||||||
|
|
||||||
|
edit: function() {
|
||||||
|
this.transitionToRoute('service.edit', this.get('id'));
|
||||||
|
},
|
||||||
|
|
||||||
|
scaleUp: function() {
|
||||||
|
this.incrementProperty('scale');
|
||||||
|
return this.save();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
availableActions: function() {
|
||||||
|
|
||||||
|
var a = this.get('actions');
|
||||||
|
|
||||||
|
var choices = [
|
||||||
|
{ label: 'Start', icon: 'ss-play', action: 'activate', enabled: !!a.activate, color: 'text-success'},
|
||||||
|
{ label: 'Stop', icon: 'ss-pause', action: 'deactivate', enabled: !!a.deactivate, color: 'text-danger'},
|
||||||
|
{ label: 'Delete', icon: 'ss-trash', action: 'promptDelete', enabled: !!a.remove, altAction: 'delete', color: 'text-warning' },
|
||||||
|
{ label: 'Purge', icon: 'ss-tornado', action: 'purge', enabled: !!a.purge },
|
||||||
|
{ divider: true },
|
||||||
|
{ label: 'View in API', icon: '', action: 'goToApi', enabled: true},
|
||||||
|
{ divider: true },
|
||||||
|
{ label: 'Edit', icon: 'ss-write', action: 'edit', enabled: !!a.update },
|
||||||
|
];
|
||||||
|
|
||||||
|
return choices;
|
||||||
|
}.property('actions.{activate,deactivate,update,remove,purge}'),
|
||||||
|
|
||||||
|
getEnvironment: function() {
|
||||||
|
return this.get('store').find('environment', this.get('environmentId'));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
LoadBalancerServiceController.reopenClass({
|
||||||
|
stateMap: {
|
||||||
|
'requested': {icon: 'ss-tag', color: 'text-danger'},
|
||||||
|
'registering': {icon: 'ss-tag', color: 'text-danger'},
|
||||||
|
'activating': {icon: 'ss-tag', color: 'text-danger'},
|
||||||
|
'active': {icon: 'ss-layergroup', color: 'text-success'},
|
||||||
|
'deactivating': {icon: 'ss-down', color: 'text-danger'},
|
||||||
|
'inactive': {icon: 'fa fa-circle', color: 'text-danger'},
|
||||||
|
'removing': {icon: 'ss-trash', color: 'text-danger'},
|
||||||
|
'removed': {icon: 'ss-trash', color: 'text-danger'},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default LoadBalancerServiceController;
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
import Cattle from 'ui/utils/cattle';
|
||||||
|
|
||||||
|
var LoadBalancerService = Cattle.TransitioningResource.extend({
|
||||||
|
type: 'service',
|
||||||
|
|
||||||
|
consumedServicesUpdated: 0,
|
||||||
|
onConsumedServicesChanged: function() {
|
||||||
|
this.incrementProperty('consumedServicesUpdated');
|
||||||
|
}.observes('consumedservices.@each.{id,name,state}'),
|
||||||
|
});
|
||||||
|
|
||||||
|
LoadBalancerService.reopenClass({
|
||||||
|
});
|
||||||
|
|
||||||
|
export default LoadBalancerService;
|
||||||
|
|
@ -112,6 +112,7 @@ Router.map(function() {
|
||||||
|
|
||||||
this.resource('environments.new', {path: '/environments/add'});
|
this.resource('environments.new', {path: '/environments/add'});
|
||||||
this.resource('service.new', {path: '/environments/add-service'});
|
this.resource('service.new', {path: '/environments/add-service'});
|
||||||
|
this.resource('service.new-balancer', {path: '/environments/add-balancer'});
|
||||||
this.resource('environments', {path: '/environments'}, function() {
|
this.resource('environments', {path: '/environments'}, function() {
|
||||||
this.route('index', {path: '/'});
|
this.route('index', {path: '/'});
|
||||||
this.resource('environment', {path: '/:environment_id'}, function() {
|
this.resource('environment', {path: '/:environment_id'}, function() {
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,8 @@ ServiceController.reopenClass({
|
||||||
'registering': {icon: 'ss-tag', color: 'text-danger'},
|
'registering': {icon: 'ss-tag', color: 'text-danger'},
|
||||||
'activating': {icon: 'ss-tag', color: 'text-danger'},
|
'activating': {icon: 'ss-tag', color: 'text-danger'},
|
||||||
'active': {icon: 'ss-layergroup', color: 'text-success'},
|
'active': {icon: 'ss-layergroup', color: 'text-success'},
|
||||||
|
'updating-active': {icon: 'ss-tag', color: 'text-success'},
|
||||||
|
'updating-inactive':{icon: 'ss-tag', color: 'text-danger'},
|
||||||
'deactivating': {icon: 'ss-down', color: 'text-danger'},
|
'deactivating': {icon: 'ss-down', color: 'text-danger'},
|
||||||
'inactive': {icon: 'fa fa-circle', color: 'text-danger'},
|
'inactive': {icon: 'fa fa-circle', color: 'text-danger'},
|
||||||
'removing': {icon: 'ss-trash', color: 'text-danger'},
|
'removing': {icon: 'ss-trash', color: 'text-danger'},
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,160 @@
|
||||||
|
import Ember from 'ember';
|
||||||
|
import Cattle from 'ui/utils/cattle';
|
||||||
|
import EditLoadBalancerConfig from 'ui/mixins/edit-loadbalancerconfig';
|
||||||
|
|
||||||
|
export default Ember.ObjectController.extend(Cattle.NewOrEditMixin, EditLoadBalancerConfig, {
|
||||||
|
queryParams: ['environmentId','tab'],
|
||||||
|
environmentId: null,
|
||||||
|
tab: 'listeners',
|
||||||
|
error: null,
|
||||||
|
editing: false,
|
||||||
|
primaryResource: Ember.computed.alias('model.balancer'),
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
addTargetService: function() {
|
||||||
|
this.get('targetsArray').pushObject({isService: true, value: null});
|
||||||
|
},
|
||||||
|
removeTarget: function(obj) {
|
||||||
|
this.get('targetsArray').removeObject(obj);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
initFields: function() {
|
||||||
|
this._super();
|
||||||
|
this.set('targetsArray', [{isService: true, value: null}]);
|
||||||
|
this.set('listenersArray', [
|
||||||
|
this.get('store').createRecord({
|
||||||
|
type: 'loadBalancerListener',
|
||||||
|
name: 'uilistener',
|
||||||
|
sourcePort: '',
|
||||||
|
sourceProtocol: 'http',
|
||||||
|
targetPort: '',
|
||||||
|
targetProtocol: 'http',
|
||||||
|
algorithm: 'roundrobin',
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
this.initUri();
|
||||||
|
},
|
||||||
|
|
||||||
|
useExisting: 'no',
|
||||||
|
isUseExisting: Ember.computed.equal('useExisting','yes'),
|
||||||
|
hasNoExisting: Ember.computed.equal('activeConfigs.length',0),
|
||||||
|
existingConfigId: null,
|
||||||
|
|
||||||
|
initHosts: function() {
|
||||||
|
},
|
||||||
|
hostDisabled: Ember.computed.equal('hostChoices.length',0),
|
||||||
|
hostChoices: function() {
|
||||||
|
return this.get('allHosts').filter((host) => {
|
||||||
|
return host.get('state') === 'active';
|
||||||
|
}).sortBy('name','id');
|
||||||
|
}.property('allHosts.@each.{id,name,state}'),
|
||||||
|
|
||||||
|
targetsArray: null,
|
||||||
|
targetServiceIds: function() {
|
||||||
|
return this.get('targetsArray').filterProperty('isService',true).filterProperty('value').map((choice) => {
|
||||||
|
return Ember.get(choice,'value');
|
||||||
|
}).uniq();
|
||||||
|
}.property('targetsArray.@each.{isService,value}'),
|
||||||
|
|
||||||
|
targetChoices: function() {
|
||||||
|
var list = [];
|
||||||
|
var env = this.get('environment');
|
||||||
|
var envName = env.get('name') || ('(Environment '+env.get('id')+')');
|
||||||
|
|
||||||
|
env.get('services').map((service) => {
|
||||||
|
list.pushObject({
|
||||||
|
group: 'Environment: ' + envName,
|
||||||
|
id: service.get('id'),
|
||||||
|
name: service.get('name') || ('(' + service.get('id') + ')')
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return list.sortBy('group','name','id');
|
||||||
|
}.property('environment.services.@each.{name,id},environment.{name,id}').volatile(),
|
||||||
|
|
||||||
|
activeConfigs: function() {
|
||||||
|
return this.get('allConfigs').filter((config) => {
|
||||||
|
return config.get('state') === 'active';
|
||||||
|
});
|
||||||
|
}.property('allConfigs.@each.state'),
|
||||||
|
|
||||||
|
validate: function() {
|
||||||
|
this._super();
|
||||||
|
var errors = this.get('errors')||[];
|
||||||
|
|
||||||
|
if ( !this.get('targetServiceIds.length') )
|
||||||
|
{
|
||||||
|
errors.push('Choose one or more targets to send traffic to');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.get('listenersArray.length') )
|
||||||
|
{
|
||||||
|
errors.push('One or more listening ports are required');
|
||||||
|
}
|
||||||
|
|
||||||
|
errors.pushObjects(this.get('config').validationErrors());
|
||||||
|
this.get('listenersArray').forEach((listener) => {
|
||||||
|
errors.pushObjects(listener.validationErrors());
|
||||||
|
});
|
||||||
|
|
||||||
|
if ( (this.get('listenersArray')||[]).filterProperty('sourcePort',8080).get('length') > 0 )
|
||||||
|
{
|
||||||
|
errors.push('Port 8080 cannot currently be used as a source port');
|
||||||
|
}
|
||||||
|
|
||||||
|
errors.pushObjects(this.get('balancer').validationErrors());
|
||||||
|
|
||||||
|
if ( errors.length )
|
||||||
|
{
|
||||||
|
this.set('errors',errors.uniq());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
has8080: function() {
|
||||||
|
// The port might be an int or a string due to validation..
|
||||||
|
return ( (this.get('listenersArray')||[]).filterProperty('sourcePort','8080').get('length') > 0 ) ||
|
||||||
|
( (this.get('listenersArray')||[]).filterProperty('sourcePort',8080).get('length') > 0 );
|
||||||
|
}.property('listenersArray.@each.sourcePort'),
|
||||||
|
|
||||||
|
listenersChanged: function() {
|
||||||
|
var list = [];
|
||||||
|
this.get('listenersArray').forEach(function(listener) {
|
||||||
|
var src = listener.get('sourcePort');
|
||||||
|
var proto = listener.get('sourceProtocol');
|
||||||
|
var tgt = listener.get('targetPort');
|
||||||
|
|
||||||
|
if ( src && proto )
|
||||||
|
{
|
||||||
|
list.pushObject(src + ':' + (tgt ? tgt : src) + (proto === 'http' ? '': '/' + proto ) );
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.set('model.launchConfig.ports', list.sort().uniq());
|
||||||
|
}.observes('listenersArray.@each.{sourcePort,sourceProtocol,targetPort,targetProtocol}'),
|
||||||
|
|
||||||
|
nameChanged: function() {
|
||||||
|
this.set('config.name', this.get('balancer.name') + ' config');
|
||||||
|
}.observes('balancer.name'),
|
||||||
|
|
||||||
|
descriptionChanged: function() {
|
||||||
|
this.set('config.description', this.get('balancer.description'));
|
||||||
|
}.observes('balancer.description'),
|
||||||
|
|
||||||
|
didSave: function() {
|
||||||
|
var balancer = this.get('model.balancer');
|
||||||
|
// Set balancer targets
|
||||||
|
return balancer.waitForNotTransitioning().then(() => {
|
||||||
|
return balancer.doAction('setservicelinks', {
|
||||||
|
serviceIds: this.get('targetServiceIds'),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
doneSaving: function() {
|
||||||
|
this.transitionToRoute('environment', this.get('environment.id'));
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,89 @@
|
||||||
|
import AuthenticatedRouteMixin from 'ui/mixins/authenticated-route';
|
||||||
|
import Ember from 'ember';
|
||||||
|
|
||||||
|
export default Ember.Route.extend(AuthenticatedRouteMixin, {
|
||||||
|
model: function(params/*, transition*/) {
|
||||||
|
var store = this.get('store');
|
||||||
|
|
||||||
|
var dependencies = [
|
||||||
|
store.findAll('host'),
|
||||||
|
store.find('environment', params.environmentId).then(function(env) {
|
||||||
|
return env.importLink('services');
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
return Ember.RSVP.all(dependencies, 'Load dependencies').then(function(results) {
|
||||||
|
var allHosts = results[0];
|
||||||
|
var environment = results[1];
|
||||||
|
|
||||||
|
var launchConfig = store.createRecord({
|
||||||
|
type: 'container',
|
||||||
|
});
|
||||||
|
|
||||||
|
var lbConfig = store.createRecord({
|
||||||
|
type: 'loadBalancerConfig',
|
||||||
|
healthCheck: store.createRecord({
|
||||||
|
type: 'loadBalancerHealthCheck',
|
||||||
|
interval: 2000,
|
||||||
|
responseTimeout: 2000,
|
||||||
|
healthyThreshold: 2,
|
||||||
|
unhealthyThreshold: 3,
|
||||||
|
requestLine: null,
|
||||||
|
}),
|
||||||
|
appCookieStickinessPolicy: null,
|
||||||
|
lbCookieStickinessPolicy: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
isService: true,
|
||||||
|
allHosts: allHosts,
|
||||||
|
environment: environment,
|
||||||
|
balancer: store.createRecord({
|
||||||
|
type: 'loadBalancerService',
|
||||||
|
name: '',
|
||||||
|
description: '',
|
||||||
|
scale: 1,
|
||||||
|
environmentId: environment.get('id'),
|
||||||
|
launchConfig: launchConfig,
|
||||||
|
loadBalancerConfig: lbConfig,
|
||||||
|
}),
|
||||||
|
config: lbConfig,
|
||||||
|
launchConfig: launchConfig,
|
||||||
|
appCookie: store.createRecord({
|
||||||
|
type: 'loadBalancerAppCookieStickinessPolicy',
|
||||||
|
mode: 'path_parameters',
|
||||||
|
requestLearn: true,
|
||||||
|
prefix: false,
|
||||||
|
timeout: 3600000,
|
||||||
|
maxLength: 1024,
|
||||||
|
}),
|
||||||
|
lbCookie: store.createRecord({
|
||||||
|
type: 'loadBalancerCookieStickinessPolicy'
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setupController: function(controller, model) {
|
||||||
|
controller.set('model',model);
|
||||||
|
controller.initFields();
|
||||||
|
},
|
||||||
|
|
||||||
|
resetController: function (controller, isExisting/*, transition*/) {
|
||||||
|
if (isExisting)
|
||||||
|
{
|
||||||
|
controller.set('tab', 'listeners');
|
||||||
|
controller.set('stickiness', 'none');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
activate: function() {
|
||||||
|
this.send('setPageLayout', {label: 'Back', backPrevious: true});
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
cancel: function() {
|
||||||
|
this.transitionTo('loadbalancers');
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
<section class="horizontal-form container-fluid">
|
||||||
|
<h2>Add Load Balancer</h2>
|
||||||
|
{{top-errors errors=errors}}
|
||||||
|
|
||||||
|
<div class="row form-group">
|
||||||
|
<div class="col-sm-12 col-md-2 form-label">
|
||||||
|
<label for="name">Name</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-12 col-md-8">
|
||||||
|
{{input id="name" type="text" value=balancer.name classNames="form-control" placeholder="e.g. Website"}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row form-group">
|
||||||
|
<div class="col-sm-12 col-md-2 form-label">
|
||||||
|
<label for="description">Description</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-12 col-md-8">
|
||||||
|
{{textarea id="description" value=balancer.description classNames="form-control no-resize" rows="5" placeholder="e.g. Balancer for mycompany.com"}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row form-group">
|
||||||
|
<div class="col-sm-12 col-md-2 form-label">
|
||||||
|
<label>Scale</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-2 col-md-1">
|
||||||
|
{{balancer.scale}}
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-10 col-md-7">
|
||||||
|
{{input-slider value=balancer.scale valueMin=1 valueMax=10 scaleMin=0}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{partial "form-divider"}}
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-xs-6 col-md-2 form-label">
|
||||||
|
<label>Targets</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6 col-md-8">
|
||||||
|
<button class="btn-circle-plus btn-circle-text" style="margin-right: 20px;" {{action "addTargetService" target="view"}}>Add Service</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12 col-md-8 col-md-offset-2">
|
||||||
|
{{partial "loadbalancer/edit-targets"}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{{partial "form-divider"}}
|
||||||
|
|
||||||
|
{{partial "loadbalancer/edit-config"}}
|
||||||
|
|
||||||
|
{{partial "save-cancel"}}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
import Ember from 'ember';
|
||||||
|
|
||||||
|
function addAction(action, selector) {
|
||||||
|
return function() {
|
||||||
|
this.get('controller').send(action);
|
||||||
|
Ember.run.next(this, function() {
|
||||||
|
this.$(selector).last().focus();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Ember.View.extend({
|
||||||
|
actions: {
|
||||||
|
addTargetService: addAction('addTargetService', '.lb-target'),
|
||||||
|
addListener: addAction('addListener', '.lb-listener-source-port'),
|
||||||
|
|
||||||
|
selectTab: function(name) {
|
||||||
|
this.set('context.tab',name);
|
||||||
|
this.$('.tab').removeClass('active');
|
||||||
|
this.$('.tab[data-section="'+name+'"]').addClass('active');
|
||||||
|
this.$('.section').addClass('hide');
|
||||||
|
this.$('.section[data-section="'+name+'"]').removeClass('hide');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
didInsertElement: function() {
|
||||||
|
$('BODY').addClass('white');
|
||||||
|
this._super();
|
||||||
|
this.send('selectTab',this.get('context.tab'));
|
||||||
|
|
||||||
|
this.$('INPUT')[0].focus();
|
||||||
|
},
|
||||||
|
|
||||||
|
willDestroyElement: function() {
|
||||||
|
$('BODY').removeClass('white');
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
@ -6,15 +6,27 @@
|
||||||
{{#if tgt.isIp}}
|
{{#if tgt.isIp}}
|
||||||
{{input type="text" class="form-control input-sm lb-target" value=tgt.value placeholder="e.g. 192.0.2.24"}}
|
{{input type="text" class="form-control input-sm lb-target" value=tgt.value placeholder="e.g. 192.0.2.24"}}
|
||||||
{{else}}
|
{{else}}
|
||||||
{{display-name-select
|
{{#if model.isService}}
|
||||||
classNames="form-control input-sm lb-target"
|
{{display-name-select
|
||||||
prompt="Select a container..."
|
classNames="form-control input-sm lb-target"
|
||||||
value=tgt.value
|
prompt="Select a service..."
|
||||||
content=targetChoices
|
value=tgt.value
|
||||||
optionValuePath="content.id"
|
content=targetChoices
|
||||||
optionLabelPath="content.name"
|
optionValuePath="content.id"
|
||||||
optionGroupPath="group"
|
optionLabelPath="content.name"
|
||||||
}}
|
optionGroupPath="group"
|
||||||
|
}}
|
||||||
|
{{else}}
|
||||||
|
{{display-name-select
|
||||||
|
classNames="form-control input-sm lb-target"
|
||||||
|
prompt="Select a container..."
|
||||||
|
value=tgt.value
|
||||||
|
content=targetChoices
|
||||||
|
optionValuePath="content.id"
|
||||||
|
optionLabelPath="content.name"
|
||||||
|
optionGroupPath="group"
|
||||||
|
}}
|
||||||
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</td>
|
</td>
|
||||||
<td width="30" class="text-right">
|
<td width="30" class="text-right">
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
<th width="30"></th>
|
<th width="30"></th>
|
||||||
<th>Target</th>
|
<th>Target</th>
|
||||||
<th width="30"></th>
|
<th width="30"></th>
|
||||||
<th>Algorithm</th>
|
<th width="100">Algorithm</th>
|
||||||
<th width="40"> </th>
|
<th width="40"> </th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|
@ -33,35 +33,43 @@
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td class="text-center"><i class="ss-right"></i></td>
|
<td class="text-center"><div class="form-control-static input-sm"><i class="ss-right"></i></div></td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
<div class="input-group input-group-sm">
|
<div class="input-group input-group-sm">
|
||||||
{{input type="text" classNames="form-control lb-listener-target-port" min="1" max="65535" step="1" value=listener.targetPort placeholder="e.g. 8080"}}
|
{{input type="text" classNames="form-control lb-listener-target-port" min="1" max="65535" step="1" value=listener.targetPort placeholder="e.g. 8080"}}
|
||||||
<div class="input-group-btn">
|
{{#if model.isService}}
|
||||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false" style="border-left: 0;">/{{listener.targetProtocol}} <span class="caret"></span></button>
|
<span class="input-group-addon">/{{listener.sourceProtocol}}</span>
|
||||||
<ul class="dropdown-menu" role="menu">
|
{{else}}
|
||||||
<li role="presentation" class="dropdown-header">
|
<div class="input-group-btn">
|
||||||
Select a protocol:
|
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false" style="border-left: 0;">/{{listener.targetProtocol}} <span class="caret"></span></button>
|
||||||
</li>
|
<ul class="dropdown-menu" role="menu">
|
||||||
{{#each choice in targetProtocolOptions}}
|
<li role="presentation" class="dropdown-header">
|
||||||
<li {{action "chooseProtocol" listener "targetProtocol" choice}}>
|
Select a protocol:
|
||||||
<a>{{choice}}</a>
|
|
||||||
</li>
|
</li>
|
||||||
{{/each}}
|
{{#each choice in targetProtocolOptions}}
|
||||||
</ul>
|
<li {{action "chooseProtocol" listener "targetProtocol" choice}}>
|
||||||
</div>
|
<a>{{choice}}</a>
|
||||||
|
</li>
|
||||||
|
{{/each}}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<td> </td>
|
<td> </td>
|
||||||
|
|
||||||
<td>
|
<td>
|
||||||
{{view "select"
|
{{#if model.isService}}
|
||||||
class="form-control input-sm"
|
<div class="form-control-static input-sm">Round Robin</div>
|
||||||
value=listener.algorithm
|
{{else}}
|
||||||
content=algorithmOptions
|
{{view "select"
|
||||||
}}
|
class="form-control input-sm"
|
||||||
|
value=listener.algorithm
|
||||||
|
content=algorithmOptions
|
||||||
|
}}
|
||||||
|
{{/if}}
|
||||||
</td>
|
</td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
<button {{action "removeListener" listener}} class="btn-circle-x" type="button" tabindex="-1"></button>
|
<button {{action "removeListener" listener}} class="btn-circle-x" type="button" tabindex="-1"></button>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "ui",
|
"name": "ui",
|
||||||
"version": "0.18.2",
|
"version": "0.19.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"directories": {
|
"directories": {
|
||||||
"doc": "doc",
|
"doc": "doc",
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"broccoli-asset-rev": "^2.0.0",
|
"broccoli-asset-rev": "^2.0.0",
|
||||||
"broccoli-sass": "0.6.2",
|
"broccoli-sass": "0.6.2",
|
||||||
"ember-api-store": "1.0.17",
|
"ember-api-store": "^1.0.17",
|
||||||
"ember-browserify": "^0.6.4",
|
"ember-browserify": "^0.6.4",
|
||||||
"ember-cli": "0.2.0",
|
"ember-cli": "0.2.0",
|
||||||
"ember-cli-app-version": "0.3.3",
|
"ember-cli-app-version": "0.3.3",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||||
|
viewBox="103.7 26 100 83.2" enable-background="new 103.7 26 100 83.2" xml:space="preserve">
|
||||||
|
<path fill="#3D8ECB" d="M148.5,26.9c4.3-2.3,9.5,0.5,11.7,4.4c1.5,2.4,2,5.3,2.5,8c-1.3,0-2.5,0.1-3.8,0.1c-0.6-2.9-1.3-6.2-3.8-8
|
||||||
|
c-2-1.7-5.3-1.5-7.1,0.5c-2.2,1.9-2.7,4.9-3.2,7.6c-1.3,0-2.6-0.1-3.8-0.1C141.7,34.4,143.6,29,148.5,26.9z"/>
|
||||||
|
<path fill="#3D8ECB" d="M135.4,41.6c1.1-0.6,2.7-0.3,3.9-0.3c0.1,9.2,0.1,18.4,0,27.6c-1.3,0-2.6,0-3.9-0.2
|
||||||
|
c-0.4-5.5-0.1-11-0.1-16.4C135.3,48.7,135,45.1,135.4,41.6z"/>
|
||||||
|
<path fill="#3D8ECB" d="M141.3,41.3c1.3,0,2.6,0,3.9,0c0.3,9.2,0.3,18.5-0.1,27.7c-1.3-0.1-2.6-0.1-3.9-0.2
|
||||||
|
C141.3,59.5,141.2,50.4,141.3,41.3z"/>
|
||||||
|
<path fill="#3D8ECB" d="M147.1,41.3c1.3-0.1,2.5-0.1,3.7-0.2c0.1,2.7-0.1,8.3-0.1,8.3l-3.7-0.1C147,49.2,146.7,44,147.1,41.3z"/>
|
||||||
|
<path fill="#3D8ECB" d="M152.9,41.3c1.3-0.1,2.7-0.1,4.1-0.1c0.1,2.8-0.1,8.5-0.1,8.5l-4-0.4C152.9,49.2,152.9,44,152.9,41.3z"/>
|
||||||
|
<path fill="#3D8ECB" d="M158.7,41.3c1.3-0.1,2.5-0.1,3.8-0.1c0,9.2-0.1,27.6-0.1,27.6l-4.1-0.1c0,0,0-15.2-0.1-22.8
|
||||||
|
C158.4,44.4,158.3,42.8,158.7,41.3z"/>
|
||||||
|
<path fill="#3D8ECB" d="M164.7,41.3l3.9-0.1v27.6l-3.8-0.1l-0.2-17.1L164.7,41.3z"/>
|
||||||
|
<path fill="#3D8ECB" d="M124.8,84.2c-0.1-3.8-0.8-8.7-4.6-10.6c-3.6-1.3-7.6-1.2-11.2-0.2c-3,1-4.5,4.3-4.8,7.2
|
||||||
|
c-0.6,4.4-0.7,9,0.5,13.3c0.7,2.9,3.3,5,6.2,5.2c3.6,0.3,7.9,0.6,10.9-1.8C125.2,93.9,124.8,88.6,124.8,84.2z M119.8,89
|
||||||
|
c-0.1,2.2-0.8,5.1-3.4,5.6c-2.4,0.3-6.1,0.6-7-2.3c-1-3.7-0.8-7.6-0.2-11.3c0.3-1.5,1.1-3,2.6-3.4c2.3-0.3,5.5-0.8,7,1.5
|
||||||
|
C120.1,82.2,119.8,85.7,119.8,89z"/>
|
||||||
|
<path fill="#3D8ECB" d="M127.5,80.2c1.7,0,3.4,0,5,0c0.2,4.8-0.5,9.7,0.3,14.4c1.7,1.9,4.5,0.2,6.4-0.6c0-4.6,0-9.2,0-13.8
|
||||||
|
c1.7,0,3.4,0,5,0c0,6.3,0,12.7,0,19c-1.3,0-2.7,0-4.1,0c-0.3-0.6,0.3-2.5-0.8-2c-1.2,0.6-5,2.9-7.8,2.1c-2.4-0.5-3.8-2.9-3.9-5.2
|
||||||
|
C127.3,89.5,127.5,84.8,127.5,80.2z"/>
|
||||||
|
<path fill="#3D8ECB" d="M164.7,80.2c1.7,0,3.6,0,5.3,0c1,3.9,2,7.9,2.9,11.8c0.2,1.3,1.1,2.4,2,3.4c1.5-5,2.7-10.1,4.1-15.2
|
||||||
|
c1.7,0,3.5,0,5.2,0c-2,7.7-4.1,15.5-6.1,23.1c-0.6,2.2-2,4-3.2,5.9c-1.2,0-2.4-0.1-3.6-0.1c0.9-3.2,1.7-6.4,2.7-9.6
|
||||||
|
c-2.2-0.7-4.6-1.7-5.2-4.1C167.3,90.4,166.2,85.3,164.7,80.2z"/>
|
||||||
|
<path fill="#3D8ECB" d="M150.6,51.1l3.3,0l0.6,8.1l-5.1,0.1L150.6,51.1z"/>
|
||||||
|
<path fill="#C0C2C4" d="M189.7,85.3c1,0,2,0.1,2.9,0.1c0,0.6,0,2,0,2.6c-1,0-2,0-2.9,0C189.7,87.4,189.7,86,189.7,85.3z"/>
|
||||||
|
<path fill="#BDBFC1" d="M189.8,89.1c0.9,0,1.8,0,2.7,0c0,3.4,0,6.7,0,10.1c-0.9,0-1.8,0-2.7,0C189.8,95.9,189.8,92.5,189.8,89.1z"/>
|
||||||
|
<path fill="#3D8ECB" d="M163.1,85c0-2.1-1.3-4.2-3.4-4.8c-4-1.1-8.2-0.3-12.2,0.6c0,1-0.1,2.2-0.1,3.2c3.1-0.1,6.2-0.6,9.3-0.2
|
||||||
|
c1.5,0.2,1,2.3,1.5,3.4c-3.4,0.3-7.8-1-10.4,1.8c-1.9,3.1-1.7,8.4,2.1,9.9c2.9,1.3,7.1-1,8.3-1.6c1.2-0.6,0.6,1.2,0.8,1.8
|
||||||
|
c1.4,0,2.7,0,4.1,0C163.1,94.5,163.4,89.7,163.1,85z M158.1,94.1c-2,0.8-4.1,1.3-6.2,1c0-0.6,0-1.3,0.1-2.1c0.2-0.8,0.4-1.3,0.6-1.7
|
||||||
|
c0.7-0.3,1.6-0.6,2.7-0.8s2-0.3,2.8-0.2C158.1,91.6,158.1,92.9,158.1,94.1z"/>
|
||||||
|
<path fill="#C0C2C4" d="M203.4,91.9c-0.9-3.1-5-3.6-7.6-2.3c-2.3,1.3-1.9,4.4-1.6,6.6c0.3,3.2,4.3,3.7,6.9,2.9
|
||||||
|
C204,98.1,204,94.3,203.4,91.9z M200.5,96.7c-0.1,0.1-0.8,0.7-1.7,0.6c-1.2-0.1-1.7-1-1.8-1.1c-0.1-0.6-0.3-1.5-0.2-2.7
|
||||||
|
c0.1-0.9,0.3-1.6,0.6-2.1c0.2-0.1,2-0.8,2.8,0c0.1,0.1,0.3,0.3,0.4,0.6c0.2,0.5,0.5,1.3,0.5,2.4S200.7,96.3,200.5,96.7z"/>
|
||||||
|
<path fill="#3D8ECB" d="M146.9,60.5c1.3,0,2.6,0,3.9,0c0.1,2.8,0.1,5.6,0,8.4c-1.3,0-2.5,0-3.8-0.2C146.6,66,146.8,63.2,146.9,60.5z
|
||||||
|
"/>
|
||||||
|
<path fill="#3D8ECB" d="M152.9,60.5l4-0.1v8.4l-4-0.1V60.5z"/>
|
||||||
|
<path fill="#C2C4C6" d="M185.1,96.7c0.9,0,1.7,0,2.7,0c0,0.7,0.1,2,0.1,2.7c-0.9-0.1-1.8-0.1-2.7-0.1
|
||||||
|
C185.1,98.5,185.1,97.3,185.1,96.7z"/>
|
||||||
|
<path fill="#3D8ECB" d="M112.4,100.5c0.9,0,1.9,0,2.8,0c1.8,1.3,4.1,1.3,6.2,1.1c0,1.3,0,2.7,0,4.1c-2.2-0.1-4.5,0.1-6.4-1.1
|
||||||
|
C113.7,103.6,113.1,101.9,112.4,100.5z"/>
|
||||||
|
<path fill="#FFFFFF" d="M159.3,97.4"/>
|
||||||
|
<path fill="#FFFFFF" d="M158.8,97.3"/>
|
||||||
|
<path fill="#FFFFFF" d="M151.3,92.9"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 4.0 KiB |
Loading…
Reference in New Issue