Define sidekicks

This commit is contained in:
Vincent Fiduccia 2015-10-14 01:04:55 -07:00
parent 292323a536
commit b2eea0ad27
12 changed files with 220 additions and 277 deletions

View File

@ -1,7 +1,6 @@
import Ember from 'ember';
import EditContainer from 'ui/mixins/edit-container';
export default Ember.Component.extend(EditContainer, {
export default Ember.Component.extend({
editing: true,
loading: true,

View File

@ -34,6 +34,32 @@
</div>
{{#unless isRequestedHost}}
{{partial "container/scheduling-rules"}}
<div class="form-control-static">
<button class="btn-circle-plus btn-circle-text" {{action "addSchedulingRule"}}> Add Scheduling Rule</button>
</div>
{{#if affinityLabelArray.length}}
<table class="table fixed no-lines no-top-padding tight small">
<thead>
<tr class="text-muted">
<th width="70"></th>
<th width="100">Condition</th>
<th width="60"></th>
<th width="180">Field</th>
<th width="30"></th>
<th>Key</th>
<th width="30"></th>
<th>Value</th>
<th width="30"></th>
</tr>
</thead>
<tbody>
{{#each labelArray as |rule|}}
{{#if (eq rule.type "affinity")}}
{{scheduling-rule-row rule=rule allHosts=allHosts remove="removeSchedulingRule" isGlobal=isGlobal}}
{{/if}}
{{/each}}
</tbody>
</table>
{{/if}}
{{/unless}}
</div>

View File

@ -17,6 +17,7 @@ export default Ember.Component.extend(NewOrEdit, SelectTab, {
isGlobal: null,
isRequestedHost: null,
portsAsStrArray: null,
launchConfigIndex: -1,
// Errors from components
commandErrors: null,
@ -30,6 +31,18 @@ export default Ember.Component.extend(NewOrEdit, SelectTab, {
portErrors: null,
actions: {
selectLaunchConfig(index) {
this.set('launchConfigIndex', index);
},
addSidekick() {
var ary = this.get('service.secondaryLaunchConfigs');
ary.pushObject(this.get('store').createRecord({
type: 'secondaryLaunchConfig',
}));
this.send('selectLaunchConfig', ary.get('length')-1);
},
setScale(scale) {
this.set('service.scale', scale);
},
@ -76,6 +89,22 @@ export default Ember.Component.extend(NewOrEdit, SelectTab, {
this.$('INPUT')[0].focus();
},
hasSidekicks: function() {
return this.get('service.secondaryLaunchConfigs.length') > 0;
}.property('service.secondaryLaunchConfigs.length'),
activeLaunchConfig: function() {
var idx = this.get('launchConfigIndex');
if( idx === -1 )
{
return this.get('launchConfig');
}
else
{
return this.get('service.secondaryLaunchConfigs').objectAt(idx);
}
}.property('launchConfigIndex'),
// ----------------------------------
// Labels
// ----------------------------------

View File

@ -1,13 +1,29 @@
<section class="horizontal-form container-fluid">
{{#if isStandalone}}
{{#unless isSidekick}}
<h2>Add {{if isService 'Service' 'Container'}}</h2>
{{top-errors errors=errors}}
{{/if}}
{{form-name-description model=primaryResource namePlaceholder="e.g. myapp" descriptionPlaceholder="My application"}}
{{/unless}}
{{#if (and isService (not isSidekick))}}
{{form-divider}}
<div class="row form-group">
<div class="col-sm-12 col-md-2 form-label r-mt5">
<label>Sidekicks</label>
</div>
<div class="col-sm-12 col-md-8">
<nav>
<ul class="pagination pagination-sm r-m0">
{{#if hasSidekicks}}
<li class="{{if (eq launchConfigIndex -1) 'active'}}"><a href="#" {{action "selectLaunchConfig" -1}}>{{default-str service.name default="(Primary Service)"}}</a></li>
{{/if}}
{{#each service.secondaryLaunchConfigs as |slc index|}}
<li class="{{if (eq launchConfigIndex index) 'active'}}"><a href="#" {{action "selectLaunchConfig" index}}>{{default-str slc.name (concat-str '(Sidekick #' (one-louder index) ')')}}</a></li>
{{/each}}
<li><a {{action "addSidekick"}} tooltip="Add Sidekick"><i class="icon icon-plus"/></a></li>
</ul>
</nav>
</div>
</div>
{{form-scale
initialLabels=launchConfig.labels
@ -18,98 +34,117 @@
setGlobal=(action 'setGlobal')
setScale=(action 'setScale')
}}
{{/if}}
{{form-divider}}
{{form-image initialValue=launchConfig.imageUuid errors=imageErrors changed=(action 'setImage')}}
{{form-divider}}
{{form-ports initialPorts=launchConfig.ports errors=portErrors portsAsStrArray=launchConfig.ports}}
{{#if isService}}
{{form-divider}}
{{form-service-links
service=service
allServices=allServices
changed=(action 'setServiceLinks')
}}
{{/if}}
</section>
{{form-divider}}
{{#if (eq launchConfigIndex -1)}}
<section class="horizontal-form container-fluid">
{{form-name-description model=primaryResource namePlaceholder="e.g. myapp" descriptionPlaceholder="My application"}}
<div class="toggle-advanced">
<a {{action "toggleAdvanced"}}>Advanced Options {{#if advanced}}<i class="icon icon-chevron-up"></i>{{else}}<i class="icon icon-chevron-down"></i>{{/if}}</a>
</div>
{{form-divider}}
<div class="{{unless advanced 'hide'}}">
<section class="text-center" style="padding: 0;">
<ul class="nav nav-pills" style="display: inline-block">
<li role="presentation" class="tab" data-section="command" {{action "selectTab" "command" target=view}}><a>Command</a></li>
<li role="presentation" class="tab" data-section="volumes" {{action "selectTab" "volumes" target=view}}><a>Volumes</a></li>
<li role="presentation" class="tab" data-section="network" {{action "selectTab" "network" target=view}}><a>Networking</a></li>
<li role="presentation" class="tab" data-section="healthcheck" {{action "selectTab" "healthcheck" target=view}}><a>Health Check</a></li>
<li role="presentation" class="tab" data-section="security" {{action "selectTab" "security" target=view}}><a>Security/Host</a></li>
<li role="presentation" class="tab" data-section="labels" {{action "selectTab" "labels" target=view}}><a>Labels</a></li>
<li role="presentation" class="tab" data-section="scheduling" {{action "selectTab" "scheduling" target=view}}><a>Scheduling</a></li>
</ul>
{{form-image initialValue=launchConfig.imageUuid errors=imageErrors changed=(action 'setImage')}}
{{form-divider}}
{{form-ports initialPorts=launchConfig.ports errors=portErrors portsAsStrArray=launchConfig.ports}}
{{#if isService}}
{{form-divider}}
{{form-service-links
service=service
allServices=allServices
changed=(action 'setServiceLinks')
}}
{{/if}}
{{form-divider}}
</section>
<section class="horizontal-form" style="background-color: #f8f9fa; margin: -7px 10px 0 10px;">
<div class="section container-fluid" data-section="command">
{{form-command instance=launchConfig errors=commandErrors}}
</div>
<div class="toggle-advanced">
<a {{action "toggleAdvanced"}}>Advanced Options {{#if advanced}}<i class="icon icon-chevron-up"></i>{{else}}<i class="icon icon-chevron-down"></i>{{/if}}</a>
</div>
<div class="section container-fluid" data-section="volumes">
{{form-volumes instance=launchConfig errors=volumeErrors allHosts=allHosts}}
</div>
<div class="{{unless advanced 'hide'}}">
<section class="text-center" style="padding: 0;">
<ul class="nav nav-pills" style="display: inline-block">
<li role="presentation" class="tab" data-section="command" {{action "selectTab" "command" target=view}}><a>Command</a></li>
<li role="presentation" class="tab" data-section="volumes" {{action "selectTab" "volumes" target=view}}><a>Volumes</a></li>
<li role="presentation" class="tab" data-section="network" {{action "selectTab" "network" target=view}}><a>Networking</a></li>
<li role="presentation" class="tab" data-section="healthcheck" {{action "selectTab" "healthcheck" target=view}}><a>Health Check</a></li>
<li role="presentation" class="tab" data-section="security" {{action "selectTab" "security" target=view}}><a>Security/Host</a></li>
<li role="presentation" class="tab" data-section="labels" {{action "selectTab" "labels" target=view}}><a>Labels</a></li>
<li role="presentation" class="tab" data-section="scheduling" {{action "selectTab" "scheduling" target=view}}><a>Scheduling</a></li>
</ul>
</section>
<div class="section container-fluid" data-section="network">
{{form-networking instance=launchConfig errors=networkingErrors allHosts=allHosts isService=isService}}
</div>
<section class="horizontal-form" style="background-color: #f8f9fa; margin: -7px 10px 0 10px;">
<div class="section container-fluid" data-section="command">
{{form-command instance=launchConfig errors=commandErrors}}
</div>
<div class="section container-fluid" data-section="healthcheck">
{{form-healthcheck healthCheck=launchConfig.healthCheck errors=healthCheckErrors}}
</div>
<div class="section container-fluid" data-section="volumes">
{{form-volumes instance=launchConfig errors=volumeErrors allHosts=allHosts}}
</div>
<div class="section" data-section="security">
{{form-security instance=launchConfig errors=securityErrors}}
</div>
<div class="section container-fluid" data-section="network">
{{form-networking instance=launchConfig errors=networkingErrors allHosts=allHosts isService=isService}}
</div>
<div class="section" data-section="labels">
<div class="row form-group">
<div class="col-sm-12 col-md-2 form-label">
<label class="form-control-static">Labels</label>
</div>
<div class="col-sm-12 col-md-8">
{{form-user-labels
initialLabels=launchConfig.labels
setLabels=(action 'setLabels' 'user')
}}
<div class="section container-fluid" data-section="healthcheck">
{{form-healthcheck healthCheck=launchConfig.healthCheck errors=healthCheckErrors}}
</div>
<div class="section" data-section="security">
{{form-security instance=launchConfig errors=securityErrors}}
</div>
<div class="section" data-section="labels">
<div class="row form-group">
<div class="col-sm-12 col-md-2 form-label">
<label class="form-control-static">Labels</label>
</div>
<div class="col-sm-12 col-md-8">
{{form-user-labels
initialLabels=launchConfig.labels
setLabels=(action 'setLabels' 'user')
}}
</div>
</div>
</div>
</div>
<div class="section" data-section="scheduling">
{{form-scheduling
isService=isService
isGlobal=isGlobal
initialHostId=launchConfig.requestedHostId
initialLabels=launchConfig.labels
errors=schedulingErrors
allHosts=allHosts
setLabels=(action 'setLabels' 'scheduling')
setGlobal=(action 'setGlobal')
setRequestedHost=(action 'setRequestedHostId')
}}
</div>
<div class="section" data-section="scheduling">
{{form-scheduling
isService=isService
isGlobal=isGlobal
initialHostId=launchConfig.requestedHostId
initialLabels=launchConfig.labels
errors=schedulingErrors
allHosts=allHosts
setLabels=(action 'setLabels' 'scheduling')
setGlobal=(action 'setGlobal')
setRequestedHost=(action 'setRequestedHostId')
}}
</div>
</section>
</div>
{{#if isStandalone}}
{{save-cancel save="save" cancel="cancel"}}
</section>
</div>
{{else}}
{{new-container
isService=true
isSidekick=true
launchConfig=activeLaunchConfig
service=activeLaunchConfig
primaryResource=activeLaunchConfig
allHosts=allHosts
allServices=allServices
}}
{{/if}}
{{#unless isSidekick}}
{{save-cancel save="save" cancel="cancel"}}
{{/unless}}

View File

@ -0,0 +1,7 @@
import Ember from 'ember';
export function concatStr(params) {
return params.join('');
}
export default Ember.Helper.helper(concatStr);

View File

@ -0,0 +1,20 @@
import Ember from 'ember';
export function defaultStr(params, options) {
var out = null;
var i = 0;
while ( !out && i < params.length)
{
out = params[i];
i++;
}
if ( !out && options && options.default)
{
out = options.default;
}
return out;
}
export default Ember.Helper.helper(defaultStr);

View File

@ -2,7 +2,7 @@ import Ember from 'ember';
export function domId(params, options) {
var obj = params[0];
return (options && options.hash && options.hash.pound ? '#' : '') + 'dom-' + obj.get('type') + '-' + obj.get('id');
return (options && options.pound ? '#' : '') + 'dom-' + obj.get('type') + '-' + obj.get('id');
}
export default Ember.Helper.helper(domId);

View File

@ -0,0 +1,7 @@
import Ember from 'ember';
export function oneLouder(params) {
return parseInt(params[0],10) + 1;
}
export default Ember.Helper.helper(oneLouder);

View File

@ -1,114 +0,0 @@
import Ember from 'ember';
import NewOrEdit from 'ui/mixins/new-or-edit';
import { debouncedObserver } from 'ui/utils/debounce';
export default Ember.Mixin.create(NewOrEdit, {
queryParams: ['tab','hostId','advanced'],
tab: 'command',
hostId: null,
advanced: false,
primaryResource: Ember.computed.alias('model.instance'),
labelResource: Ember.computed.alias('model.instance'),
isGlobal: null,
isService: null,
isRequestedHost: null,
portsAsStrArray: null,
// Errors from components
commandErrors: null,
volumeErrors: null,
networkingErrors: null,
healthCheckErrors: null,
schedulingErrors: null,
securityErrors: null,
scaleErrors: null,
imageErrors: null,
portErrors: null,
actions: {
toggleAdvanced: function() {
this.set('advanced', !this.get('advanced'));
},
setLabels(section,labels) {
this.set(section+'Labels', labels);
},
setRequestedHostId(hostId) {
console.log('set requestedHostId=',hostId);
this.set('model.instance.requestedHostId', hostId);
},
setGlobal(bool) {
console.log('setGlobal',bool);
this.set('isGlobal', bool);
},
},
// ----------------------------------
// Setup
// ----------------------------------
initFields: function() {
this._super();
this.initLabels();
},
// ----------------------------------
// Labels
// ----------------------------------
userLabels: null,
scaleLabels: null,
schedulingLabels: null,
initLabels: function() {
this.labelsChanged();
},
labelsChanged: debouncedObserver(
'userLabels.@each.{key,value}',
'scaleLabels.@each.{key,value}',
'schedulingLabels.@each.{key,value}',
function() {
var out = {};
(this.get('userLabels')||[]).forEach((row) => { out[row.key] = row.value; });
(this.get('scaleLabels')||[]).forEach((row) => { out[row.key] = row.value; });
(this.get('schedulingLabels')||[]).forEach((row) => { out[row.key] = row.value; });
if ( this.get('labelResource') )
{
console.log('set',out);
this.set('labelResource.labels', out);
}
}
),
// ----------------------------------
// Save
// ----------------------------------
willSave: function() {
var errors = [];
if ( !this.get('editing') )
{
// Errors from components
errors.pushObjects(this.get('commandErrors')||[]);
errors.pushObjects(this.get('volumeErrors')||[]);
errors.pushObjects(this.get('networkingErrors')||[]);
errors.pushObjects(this.get('healthCheckErrors')||[]);
errors.pushObjects(this.get('schedulingErrors')||[]);
errors.pushObjects(this.get('securityErrors')||[]);
errors.pushObjects(this.get('scaleErrors')||[]);
errors.pushObjects(this.get('imageErrors')||[]);
errors.pushObjects(this.get('portErrors')||[]);
if ( errors.length )
{
this.set('errors', errors);
return false;
}
}
return this._super();
},
});

View File

@ -21,10 +21,12 @@ export default Ember.Route.extend({
}
return Ember.RSVP.all(dependencies, 'Load container dependencies').then((results) => {
var store = this.get('store');
var allHosts = results[0];
var allServices = results[1];
var serviceOrContainer = results[2];
var serviceLinks = [];
var secondaryLaunchConfigs = [];
var instanceData, serviceData, healthCheckData;
if ( serviceOrContainer )
@ -36,6 +38,12 @@ export default Ember.Route.extend({
instanceData = serviceData.launchConfig;
delete serviceData.launchConfig;
delete serviceData.instances;
(serviceOrContainer.secondaryLaunchConfigs||[]).forEach((slc) => {
var data = slc.serializeForNew();
secondaryLaunchConfigs.push(store.createRecord(data));
});
delete serviceData.secondaryLaunchConfigs;
}
else
@ -64,8 +72,7 @@ export default Ember.Route.extend({
};
}
var instance = this.get('store').createRecord(instanceData);
var instance = store.createRecord(instanceData);
var service = store.createRecord(serviceData);
service.set('serviceLinks', serviceLinks);
@ -76,7 +83,8 @@ export default Ember.Route.extend({
instance.set('healthCheck', store.createRecord(healthCheckData));
}
service.set('launchConfig', instance); // Creating a service needs the isntance definition here
service.set('launchConfig', instance);
service.set('secondaryLaunchConfigs', secondaryLaunchConfigs);
return Ember.Object.create({
service: service,

View File

@ -444,7 +444,7 @@ TABLE.graphs {
}
// adds text indent with a 5px step through 15 layers
@for $i from 1 through 15 {
@for $i from 0 through 15 {
.indent-#{$i} { text-indent: 10px * $i; }
}
@ -462,7 +462,7 @@ $spacing-property-map: (
pl: padding-left,
pr: padding-right
);
@for $size from 1 through 5 {
@for $size from 0 through 5 {
$val: $size * 5px;
@each $keyword, $property in $spacing-property-map {
.r-#{$keyword}#{$size*5} {
@ -471,11 +471,6 @@ $spacing-property-map: (
}
}
// SS-Gizmo doesn't know how to vertical align..
.ss-icon, [class^="ss-"] {
vertical-align: -4%;
}
.btn-circle {
display: inline-block;
line-height: $line-height-base;

View File

@ -1,69 +0,0 @@
<div class="toggle-advanced">
<a {{action "toggleAdvanced"}}>Advanced Options {{#if advanced}}<i class="icon icon-chevron-up"></i>{{else}}<i class="icon icon-chevron-down"></i>{{/if}}</a>
</div>
<div class="{{unless advanced 'hide'}}">
<section class="text-center" style="padding: 0;">
<ul class="nav nav-pills" style="display: inline-block">
<li role="presentation" class="tab" data-section="command" {{action "selectTab" "command" target=view}}><a>Command</a></li>
<li role="presentation" class="tab" data-section="volumes" {{action "selectTab" "volumes" target=view}}><a>Volumes</a></li>
<li role="presentation" class="tab" data-section="network" {{action "selectTab" "network" target=view}}><a>Networking</a></li>
<li role="presentation" class="tab" data-section="healthcheck" {{action "selectTab" "healthcheck" target=view}}><a>Health Check</a></li>
<li role="presentation" class="tab" data-section="security" {{action "selectTab" "security" target=view}}><a>Security/Host</a></li>
<li role="presentation" class="tab" data-section="labels" {{action "selectTab" "labels" target=view}}><a>Labels</a></li>
<li role="presentation" class="tab" data-section="scheduling" {{action "selectTab" "scheduling" target=view}}><a>Scheduling</a></li>
</ul>
</section>
<section class="horizontal-form" style="background-color: #f8f9fa; margin: -7px 10px 0 10px;">
<div class="section container-fluid" data-section="command">
{{form-command instance=model.instance errors=commandErrors}}
</div>
<div class="section container-fluid" data-section="volumes">
{{form-volumes instance=model.instance errors=volumeErrors allHosts=model.allHosts}}
</div>
<div class="section container-fluid" data-section="network">
{{form-networking instance=model.instance errors=networkingErrors allHosts=model.allHosts}}
</div>
<div class="section container-fluid" data-section="healthcheck">
{{form-healthcheck healthCheck=model.instance.healthCheck errors=healthCheckErrors}}
</div>
<div class="section" data-section="security">
{{form-security instance=model.instance errors=securityErrors}}
</div>
<div class="section" data-section="labels">
<div class="row form-group">
<div class="col-sm-12 col-md-2 form-label">
<label class="form-control-static">Labels</label>
</div>
<div class="col-sm-12 col-md-8">
{{form-user-labels
initialLabels=labelResource.labels
setLabels=(action 'setLabels' 'user')
}}
</div>
</div>
</div>
<div class="section" data-section="scheduling">
{{form-scheduling
isService=isService
isGlobal=isGlobal
initialHostId=model.instance.requestedHostId
initialLabels=labelResource.labels
errors=schedulingErrors
allHosts=model.allHosts
setLabels=(action 'setLabels' 'scheduling')
setGlobal=(action 'setGlobal')
setRequestedHost=(action 'setRequestedHostId')
}}
</div>
</section>
</div>