Add new snapshot timeline (#800)

This commit is contained in:
Westly Wright 2016-08-01 21:27:30 -07:00 committed by Vincent Fiduccia
parent 1c5980c571
commit 036d42aef7
67 changed files with 1368 additions and 746 deletions

View File

@ -10,6 +10,7 @@ export default Ember.Controller.extend({
tooltipService : Ember.inject.service('tooltip'),
tooltip : Ember.computed.alias('tooltipService.tooltipOpts.type'),
tooltipTemplate : Ember.computed.alias('tooltipService.tooltipOpts.template'),
error : null,
error_description : null,

View File

@ -53,4 +53,4 @@
</div>
</div>
{{component tooltip class="container-tooltip" id="tooltip-base" role="tooltip" aria-hidden="false"}}
{{component tooltip tooltipTemplate=tooltipTemplate class="container-tooltip" id="tooltip-base" role="tooltip" aria-hidden="false"}}

View File

@ -0,0 +1,4 @@
import Ember from 'ember';
export default Ember.Controller.extend({
});

View File

@ -0,0 +1,7 @@
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return [ ];
},
});

View File

@ -0,0 +1,4 @@
<section>
<div class="well">
</div>
</section>

View File

@ -42,6 +42,8 @@ export default Ember.Route.extend(Subscribe, {
let isAdmin = (type === C.USER.TYPE_ADMIN) || !this.get('access.enabled');
this.set('access.admin', isAdmin);
var store = this.get('store');
return Ember.RSVP.hash({
schemas: this.loadUserSchemas(),
projects: this.loadProjects(),
@ -54,6 +56,10 @@ export default Ember.Route.extend(Subscribe, {
projectId = transition.params['authenticated.project'].project_id;
}
if (this.get(`prefs.${C.PREFS.I_HATE_SPINNERS}`)) {
Ember.$('BODY').addClass('i-hate-spinners');
}
// Make sure a valid project is selected
return this.get('projects').selectDefault(projectId).then((project) => {
// Load stuff that is needed to draw the header
@ -62,10 +68,12 @@ export default Ember.Route.extend(Subscribe, {
return Ember.RSVP.hash({
language: this.get('language').setLanguage(),
orchestrationState: this.get('projects').updateOrchestrationState(),
hosts: this.get('store').findAllUnremoved('host'),
machines: this.get('store').findAllUnremoved('machine'),
stacks: this.get('store').findAllUnremoved('environment'),
mounts: this.get('store').findAllUnremoved('mount'), // the container model needs access
hosts: store.findAllUnremoved('host'),
machines: store.findAllUnremoved('machine'),
stacks: store.findAllUnremoved('environment'),
mounts: store.findAllUnremoved('mount'), // the container model needs access
volumes: store.findAllUnremoved('volume'),
snapshots: store.findAllUnremoved('snapshot'),
}).then((moreHash) => {
Ember.merge(hash, moreHash);

View File

@ -1,17 +1,20 @@
import Ember from 'ember';
const { computed, get/*, set*/ } = Ember;
export default Ember.Component.extend({
intl: Ember.inject.service(),
intl: Ember.inject.service(),
rSelected: false,
wSelected: false,
mSelected: false,
rSelected: false,
wSelected: false,
mSelected: false,
editing: false,
selection: null,
selection: null,
init: function() {
this._super();
var sel = this.get('initialSelection');
var sel = get(this, 'initialSelection');
this.setProperties({
rSelected: sel.indexOf('r') >= 0,
wSelected: sel.indexOf('w') >= 0,
@ -27,28 +30,56 @@ export default Ember.Component.extend({
},
didInsertElement: function() {
var moreClass = this.get('buttonClass')||'';
var opts = {
buttonClass: 'btn btn-default' + (moreClass ? ' '+moreClass : ''),
numberDisplayed: 2,
nonSelectedText: this.get('intl').t('devicePermissions.none'),
allSelectedText: this.get('intl').t('devicePermissions.all'),
if (get(this, 'editing')) {
var moreClass = get(this, 'buttonClass')||'';
var opts = {
buttonClass: 'btn btn-default' + (moreClass ? ' '+moreClass : ''),
numberDisplayed: 2,
nonSelectedText: get(this, 'intl').t('devicePermissions.none'),
allSelectedText: get(this, 'intl').t('devicePermissions.all'),
templates: {
li: '<li><a tabindex="0"><label></label></a></li>',
},
};
templates: {
li: '<li><a tabindex="0"><label></label></a></li>',
},
};
this.$('SELECT').multiselect(opts);
this.$('SELECT').multiselect(opts);
}
},
humanReadableList: computed('initialSelection', function() {
let permissions = get(this, 'initialSelection').split('');
let out = [];
permissions.forEach((perm) => {
switch (perm) {
case 'r':
out.push(get(this, 'intl').tHtml('devicePermissions.read'));
break;
case 'w':
out.push(get(this, 'intl').tHtml('devicePermissions.write'));
break;
case 'm':
out.push(get(this, 'intl').tHtml('devicePermissions.mknod'));
break;
default:
break;
}
});
return out.join('/');
}),
rebuild: function() {
Ember.run.next(() => {
this.$('SELECT').multiselect('setOptions', {
nonSelectedText: this.get('intl').t('devicePermissions.none'),
allSelectedText: this.get('intl').t('devicePermissions.all'),
});
this.$('SELECT').multiselect('rebuild');
if (get(this, 'editing')) {
this.$('SELECT').multiselect('setOptions', {
nonSelectedText: get(this, 'intl').t('devicePermissions.none'),
allSelectedText: get(this, 'intl').t('devicePermissions.all'),
});
this.$('SELECT').multiselect('rebuild');
}
});
}.observes('intl._locale'),
});

View File

@ -1,5 +1,9 @@
<select class="form-control" multiple=true onchange={{action "selectChanged" target.value}}>
<option value="r" selected={{rSelected}}>{{t 'devicePermissions.read'}}</option>
<option value="w" selected={{wSelected}}>{{t 'devicePermissions.write'}}</option>
<option value="m" selected={{mSelected}}>{{t 'devicePermissions.mknod'}}</option>
</select>
{{#if editing}}
<select class="form-control" multiple=true onchange={{action "selectChanged" target.value}}>
<option value="r" selected={{rSelected}}>{{t 'devicePermissions.read'}}</option>
<option value="w" selected={{wSelected}}>{{t 'devicePermissions.write'}}</option>
<option value="m" selected={{mSelected}}>{{t 'devicePermissions.mknod'}}</option>
</select>
{{else}}
{{humanReadableList}}
{{/if}}

View File

@ -7,8 +7,10 @@ export default Ember.Component.extend(ManageLabels, {
instance: null,
errors: null,
isService: null,
editing: true,
tagName: '',
intl: Ember.inject.service(),
init() {
this._super(...arguments);
@ -30,25 +32,32 @@ export default Ember.Component.extend(ManageLabels, {
var instance = this.get('instance');
var tty = instance.get('tty');
var stdin = instance.get('stdinOpen');
var out = 'both';
var out = {
type: 'both',
name: this.get('intl').tHtml('formCommand.console.both'),
};
if ( tty !== undefined || stdin !== undefined )
{
if ( tty && stdin )
{
out = 'both';
out.type = 'both';
out.name = this.get('intl').tHtml('formCommand.console.both');
}
else if ( tty )
{
out = 'terminal';
out.type = 'terminal';
out.name = this.get('intl').tHtml('formCommand.console.terminal');
}
else if ( stdin )
{
out = 'interactive';
out.type = 'interactive';
out.name = this.get('intl').tHtml('formCommand.console.interactive');
}
else
{
out = 'none';
out.type = 'none';
out.name = this.get('intl').tHtml('formCommand.console.none');
}
}
@ -59,7 +68,7 @@ export default Ember.Component.extend(ManageLabels, {
terminalDidChange: function() {
var val = this.get('terminal');
var stdinOpen = ( val === 'interactive' || val === 'both' );
var tty = (val === 'terminal' || val === 'both');
var tty = (val.type === 'terminal' || val.type === 'both');
this.set('instance.tty', tty);
this.set('instance.stdinOpen', stdinOpen);
}.observes('terminal'),

View File

@ -4,7 +4,9 @@
</div>
<div class="col-sm-12 col-md-8">
{{input-command class="form-control" type="text" changed=(action (mut instance.command)) initialValue=instance.command placeholder=(t 'formCommand.command.placeholder')}}
{{#input-or-display editable=editing value=instance.command}}
{{input-command class="form-control" type="text" changed=(action (mut instance.command)) initialValue=instance.command placeholder=(t 'formCommand.command.placeholder')}}
{{/input-or-display}}
</div>
</div>
<div class="row form-group">
@ -12,7 +14,9 @@
<label class="form-control-static">{{t 'formCommand.entryPoint.label'}}</label>
</div>
<div class="col-sm-12 col-md-8">
{{input-command class="form-control" type="text" changed=(action (mut instance.entryPoint)) initialValue=instance.entryPoint placeholder=(t 'formCommand.entryPoint.placeholder')}}
{{#input-or-display editable=editing value=instance.entryPoint}}
{{input-command class="form-control" type="text" changed=(action (mut instance.entryPoint)) initialValue=instance.entryPoint placeholder=(t 'formCommand.entryPoint.placeholder')}}
{{/input-or-display}}
</div>
</div>
<div class="row form-group">
@ -20,13 +24,17 @@
<label class="form-control-static">{{t 'formCommand.workingDir.label'}}</label>
</div>
<div class="col-sm-12 col-md-4">
{{input type="text" value=instance.workingDir classNames="form-control" placeholder=(t 'formCommand.workingDir.placeholder')}}
{{#input-or-display editable=editing value=instance.workingDir}}
{{input type="text" value=instance.workingDir classNames="form-control" placeholder=(t 'formCommand.workingDir.placeholder')}}
{{/input-or-display}}
</div>
<div class="col-sm-12 col-md-1 form-label" style="text-align: left">
<label class="form-control-static">{{t 'formCommand.user.label'}}</label>
</div>
<div class="col-sm-12 col-md-3">
{{input type="text" value=instance.user classNames="form-control" placeholder=(t 'formCommand.user.placeholder')}}
{{#input-or-display editable=editing value=instance.user}}
{{input type="text" value=instance.user classNames="form-control" placeholder=(t 'formCommand.user.placeholder')}}
{{/input-or-display}}
</div>
</div>
@ -35,29 +43,33 @@
<label>{{t 'formCommand.console.label'}}</label>
</div>
<div class="col-xs-12 col-sm-6 col-md-4">
<div class="radio small">
<label>{{radio-button selection=terminal value="both"}} {{format-html-message 'formCommand.console.both'}}</label>
{{#input-or-display editable=editing value=terminal.name}}
<div class="col-xs-12 col-sm-6 col-md-4">
<div class="radio small">
<label>{{radio-button selection=terminal.type value="both"}} {{format-html-message 'formCommand.console.both'}}</label>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-4">
<div class="radio small">
<label>{{radio-button selection=terminal value="interactive"}} {{format-html-message 'formCommand.console.interactive'}}</label>
<div class="col-xs-12 col-sm-6 col-md-4">
<div class="radio small">
<label>{{radio-button selection=terminal.type value="interactive"}} {{format-html-message 'formCommand.console.interactive'}}</label>
</div>
</div>
</div>
{{/input-or-display}}
</div>
<div class="row form-group">
<div class="hidden-xs hidden-sm col-md-2 form-label">&nbsp;</div>
<div class="col-xs-12 col-sm-6 col-md-4">
<div class="radio small">
<label>{{radio-button selection=terminal value="terminal"}} {{format-html-message 'formCommand.console.terminal'}}</label>
{{#if editing}}
<div class="hidden-xs hidden-sm col-md-2 form-label">&nbsp;</div>
<div class="col-xs-12 col-sm-6 col-md-4">
<div class="radio small">
<label>{{radio-button selection=terminal.type value="terminal"}} {{format-html-message 'formCommand.console.terminal'}}</label>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-4">
<div class="radio small">
<label>{{radio-button selection=terminal value="none"}} {{format-html-message 'formCommand.console.none'}}</label>
<div class="col-xs-12 col-sm-6 col-md-4">
<div class="radio small">
<label>{{radio-button selection=terminal.type value="none"}} {{format-html-message 'formCommand.console.none'}}</label>
</div>
</div>
</div>
{{/if}}
</div>
{{#if isService}}
@ -66,16 +78,24 @@
<label>{{t 'formCommand.autoRestart.label'}}</label>
</div>
<div class="col-xs-12 col-sm-6 col-md-4">
<div class="radio small">
<label>{{radio-button selection=startOnce value=false}} {{t 'formCommand.autoRestart.startOnceFalse'}}</label>
{{#if editing}}
<div class="col-xs-12 col-sm-6 col-md-4">
<div class="radio small">
<label>{{radio-button selection=startOnce value=false}} {{t 'formCommand.autoRestart.startOnceFalse'}}</label>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-4">
<div class="radio small">
<label>{{radio-button selection=startOnce value=true}} {{t 'formCommand.autoRestart.startOnceTrue'}}</label>
<div class="col-xs-12 col-sm-6 col-md-4">
<div class="radio small">
<label>{{radio-button selection=startOnce value=true}} {{t 'formCommand.autoRestart.startOnceTrue'}}</label>
</div>
</div>
</div>
{{else}}
{{#if startOnce}}
<div>{{startOnce}}</div>
{{else}}
<div>{{t 'generic.none'}}</div>
{{/if}}
{{/if}}
</div>
{{else}}
<div class="row">
@ -83,37 +103,49 @@
<label>{{t 'formCommand.autoRestart.label'}}</label>
</div>
<div class="col-xs-12 col-sm-6 col-md-4">
<div class="radio small">
<label>{{radio-button selection=restart value="no"}} {{t 'formCommand.autoRestart.no'}}</label>
{{#if editing}}
<div class="col-xs-12 col-sm-6 col-md-4">
<div class="radio small">
<label>{{radio-button selection=restart value="no"}} {{t 'formCommand.autoRestart.no'}}</label>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-4">
<div class="radio small">
<label>{{radio-button selection=restart value="on-failure"}} {{format-html-message 'formCommand.autoRestart.onFailure'}}</label>
<div class="col-xs-12 col-sm-6 col-md-4">
<div class="radio small">
<label>{{radio-button selection=restart value="on-failure"}} {{format-html-message 'formCommand.autoRestart.onFailure'}}</label>
</div>
</div>
</div>
{{else}}
<div class="col-xs-12 col-sm-6 col-md-4">
{{#if restart}}
<div>{{restart}}</div>
{{else}}
<div>{{t 'generic.none'}}</div>
{{/if}}
</div>
{{/if}}
</div>
<div class="row">
<div class="hidden-xs hidden-sm col-md-2 form-label">&nbsp;</div>
<div class="col-xs-12 col-sm-6 col-md-4">
<div class="radio small">
<label>{{radio-button selection=restart value="always"}} {{t 'formCommand.autoRestart.always'}}</label>
{{#if editing}}
<div class="row">
<div class="hidden-xs hidden-sm col-md-2 form-label">&nbsp;</div>
<div class="col-xs-12 col-sm-6 col-md-4">
<div class="radio small">
<label>{{radio-button selection=restart value="always"}} {{t 'formCommand.autoRestart.always'}}</label>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-4">
<div class="radio small">
<label>
{{radio-button selection=restart value="on-failure-cond"}}
<span class="with-input">
{{t 'formCommand.autoRestart.onFailureCondPrefix' limit=restartLimit}}
{{input type="number" min=1 safeStyle="width: 60px; padding: 0 2px; display: inline-block;" class="form-control input-sm" value=restartLimit}}
{{t 'formCommand.autoRestart.onFailureCondSuffix' limit=restartLimit}}
</span>
</label>
</div>
</div>
</div>
<div class="col-xs-12 col-sm-6 col-md-4">
<div class="radio small">
<label>
{{radio-button selection=restart value="on-failure-cond"}}
<span class="with-input">
{{t 'formCommand.autoRestart.onFailureCondPrefix' limit=restartLimit}}
{{input type="number" min=1 safeStyle="width: 60px; padding: 0 2px; display: inline-block;" class="form-control input-sm" value=restartLimit}}
{{t 'formCommand.autoRestart.onFailureCondSuffix' limit=restartLimit}}
</span>
</label>
</div>
</div>
</div>
{{/if}}
{{/if}}
<div class="row">
@ -131,6 +163,7 @@
valueLabel="formCommand.environment.valueLabel"
valuePlaceholder="formCommand.environment.valuePlaceholder"
allowEmptyValue=true
editing=editing
}}
</div>
</div>

View File

@ -3,15 +3,23 @@
<label class="form-control-static">{{t 'formHealthCheck.label'}}</label>
</div>
<div class="col-sm-12 col-md-9">
<div class="radio input pull-left r-mr20">
<label class="form-control-static">{{radio-button selection=checkType value="none"}} {{t 'formHealthCheck.checkType.none'}}</label>
</div>
<div class="radio input pull-left r-mr20">
<label class="form-control-static">{{radio-button selection=checkType value="tcp"}} {{t 'formHealthCheck.checkType.tcp'}}</label>
</div>
<div class="radio input pull-left">
<label class="form-control-static">{{radio-button selection=checkType value="http"}} {{t 'formHealthCheck.checkType.http'}}</label>
</div>
{{#if editing}}
<div class="radio input pull-left r-mr20">
<label class="form-control-static">{{radio-button selection=checkType value="none"}} {{t 'formHealthCheck.checkType.none'}}</label>
</div>
<div class="radio input pull-left r-mr20">
<label class="form-control-static">{{radio-button selection=checkType value="tcp"}} {{t 'formHealthCheck.checkType.tcp'}}</label>
</div>
<div class="radio input pull-left">
<label class="form-control-static">{{radio-button selection=checkType value="http"}} {{t 'formHealthCheck.checkType.http'}}</label>
</div>
{{else}}
{{#if checkType}}
<div class="form-control-static">{{checkType}}</div>
{{else}}
<div class="form-control-static">{{t 'generic.none'}}</div>
{{/if}}
{{/if}}
</div>
</div>
@ -21,7 +29,9 @@
<label class="form-control-static">{{t 'formHealthCheck.port.label'}}*</label>
</div>
<div class="col-sm-12 col-md-3">
{{input type="number" min="1" max="65535" classNames="form-control" placeholder=(t 'formHealthCheck.port.placeholder') value=healthCheck.port}}
{{#input-or-display editable=editing value=healthCheck.port}}
{{input type="number" min="1" max="65535" classNames="form-control" placeholder=(t 'formHealthCheck.port.placeholder') value=healthCheck.port}}
{{/input-or-display}}
</div>
</div>
@ -31,37 +41,39 @@
<label class="form-control-static">{{t 'formHealthCheck.request.label'}}*</label>
</div>
<div class="col-sm-12 col-md-8">
<div class="input-group">
<div class="input-group-btn">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">{{uriMethod}} <i class="icon icon-chevron-down"></i></button>
<ul class="dropdown-menu" role="menu">
<li role="presentation" class="dropdown-header">
{{t 'formHealthCheck.method.prompt'}}
</li>
{{#each uriMethodChoices as |choice|}}
<li {{action "chooseUriMethod" choice}}>
<a href="#">{{choice}}</a>
</li>
{{/each}}
</ul>
</div>
{{#input-or-display editable=editing value=healthCheck.requestLine}}
<div class="input-group">
<div class="input-group-btn">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">{{uriMethod}} <i class="icon icon-chevron-down"></i></button>
<ul class="dropdown-menu" role="menu">
<li role="presentation" class="dropdown-header">
{{t 'formHealthCheck.method.prompt'}}
</li>
{{#each uriMethodChoices as |choice|}}
<li {{action "chooseUriMethod" choice}}>
<a href="#">{{choice}}</a>
</li>
{{/each}}
</ul>
</div>
{{input type="text" classNames="form-control" placeholder=(t 'formHealthCheck.path.placeholder') value=uriPath}}
{{input type="text" classNames="form-control" placeholder=(t 'formHealthCheck.path.placeholder') value=uriPath}}
<div class="input-group-btn">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">{{uriVersion}} <i class="icon icon-chevron-down"></i></button>
<ul class="dropdown-menu" role="menu">
<li role="presentation" class="dropdown-header">
{{t 'formHealthCheck.version.prompt'}}
</li>
{{#each uriVersionChoices as |choice|}}
<li {{action "chooseUriVersion" choice}}>
<a href="#">{{choice}}</a>
</li>
{{/each}}
</ul>
</div>
</div>
<div class="input-group-btn">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">{{uriVersion}} <i class="icon icon-chevron-down"></i></button>
<ul class="dropdown-menu" role="menu">
<li role="presentation" class="dropdown-header">
{{t 'formHealthCheck.version.prompt'}}
</li>
{{#each uriVersionChoices as |choice|}}
<li {{action "chooseUriVersion" choice}}>
<a href="#">{{choice}}</a>
</li>
{{/each}}
</ul>
</div>
</div>
{{/input-or-display}}
</div>
</div>
{{#if showUriHost}}
@ -70,7 +82,9 @@
<label class="form-control-static">{{t 'formHealthCheck.host.label'}}</label>
</div>
<div class="col-sm-12 col-md-8">
{{input type="text" classNames="form-control" placeholder=(t 'formHealthCheck.host.placeholder') value=uriHost}}
{{#input-or-display editable=editing value=uriHost}}
{{input type="number" min="1" max="65535" classNames="form-control" placeholder=(t 'formHealthCheck.port.placeholder') value=healthCheck.port}}
{{/input-or-display}}
</div>
</div>
{{/if}}
@ -82,19 +96,23 @@
<label class="form-control-static">{{t 'formHealthCheck.initializingTimeout.label'}}</label>
</div>
<div class="col-sm-12 col-md-3">
<div class="input-group">
{{input type="number" step=100 classNames="form-control" value=healthCheck.initializingTimeout}}
<span class="input-group-addon">{{t 'formHealthCheck.initializingTimeout.unit'}}</span>
</div>
{{#input-or-display editable=editing value=healthCheck.initializingTimeout}}
<div class="input-group">
{{input type="number" step=100 classNames="form-control" value=healthCheck.initializingTimeout}}
<span class="input-group-addon">{{t 'formHealthCheck.initializingTimeout.unit'}}</span>
</div>
{{/input-or-display}}
</div>
<div class="col-sm-12 col-md-2 form-label">
<label class="form-control-static">{{t 'formHealthCheck.reinitializingTimeout.label'}}</label>
</div>
<div class="col-sm-12 col-md-3">
<div class="input-group">
{{input type="number" step=100 classNames="form-control" value=healthCheck.reinitializingTimeout}}
<span class="input-group-addon">{{t 'formHealthCheck.reinitializingTimeout.unit'}}</span>
</div>
{{#input-or-display editable=editing value=healthCheck.reinitializingTimeout}}
<div class="input-group">
{{input type="number" step=100 classNames="form-control" value=healthCheck.reinitializingTimeout}}
<span class="input-group-addon">{{t 'formHealthCheck.reinitializingTimeout.unit'}}</span>
</div>
{{/input-or-display}}
</div>
</div>
@ -104,19 +122,23 @@
<label class="form-control-static">{{t 'formHealthCheck.interval.label'}}</label>
</div>
<div class="col-sm-12 col-md-3">
<div class="input-group">
{{input type="number" min=1 step=1000 classNames="form-control" value=healthCheck.interval}}
<span class="input-group-addon">{{t 'formHealthCheck.interval.unit'}}</span>
</div>
{{#input-or-display editable=editing value=healthCheck.interval}}
<div class="input-group">
{{input type="number" min=1 step=1000 classNames="form-control" value=healthCheck.interval}}
<span class="input-group-addon">{{t 'formHealthCheck.interval.unit'}}</span>
</div>
{{/input-or-display}}
</div>
<div class="col-sm-12 col-md-2 form-label">
<label class="form-control-static">{{t 'formHealthCheck.timeout.label'}}</label>
</div>
<div class="col-sm-12 col-md-3">
<div class="input-group">
{{input type="number" min=1 step=100 classNames="form-control" value=healthCheck.responseTimeout}}
<span class="input-group-addon">{{t 'formHealthCheck.timeout.unit'}}</span>
</div>
{{#input-or-display editable=editing value=healthCheck.responseTimeout}}
<div class="input-group">
{{input type="number" min=1 step=100 classNames="form-control" value=healthCheck.responseTimeout}}
<span class="input-group-addon">{{t 'formHealthCheck.timeout.unit'}}</span>
</div>
{{/input-or-display}}
</div>
</div>
@ -125,19 +147,23 @@
<label class="form-control-static">{{t 'formHealthCheck.healthyThreshold.label'}}</label>
</div>
<div class="col-sm-12 col-md-3">
<div class="input-group">
{{input type="number" min=1 step=1 classNames="form-control" value=healthCheck.healthyThreshold}}
<span class="input-group-addon">{{t 'formHealthCheck.healthyThreshold.unit'}}</span>
</div>
{{#input-or-display editable=editing value=healthCheck.healthyThreshold}}
<div class="input-group">
{{input type="number" min=1 step=1 classNames="form-control" value=healthCheck.healthyThreshold}}
<span class="input-group-addon">{{t 'formHealthCheck.healthyThreshold.unit'}}</span>
</div>
{{/input-or-display}}
</div>
<div class="col-sm-12 col-md-2 form-label">
<label class="form-control-static">{{t 'formHealthCheck.unhealthyThreshold.label'}}</label>
</div>
<div class="col-sm-12 col-md-3">
<div class="input-group">
{{input type="number" min=1 step=1 classNames="form-control" value=healthCheck.unhealthyThreshold}}
<span class="input-group-addon">{{t 'formHealthCheck.unhealthyThreshold.unit'}}</span>
</div>
{{#input-or-display editable=editing value=healthCheck.unhealthyThreshold}}
<div class="input-group">
{{input type="number" min=1 step=1 classNames="form-control" value=healthCheck.unhealthyThreshold}}
<span class="input-group-addon">{{t 'formHealthCheck.unhealthyThreshold.unit'}}</span>
</div>
{{/input-or-display}}
</div>
</div>
@ -147,6 +173,7 @@
<label>{{t 'formHealthCheck.strategy.label'}}</label>
</div>
<div class="col-sm-12 col-md-8">
{{#input-or-display editable=editing value=strategy}}
<div class="radio input">
<label>{{radio-button selection=strategy value="none"}} {{t 'formHealthCheck.strategy.none'}}</label>
</div>
@ -163,6 +190,7 @@
</span>
</label>
</div>
{{/input-or-display}}
</div>
</div>
{{/if}}

View File

@ -58,18 +58,18 @@ function removeEmptyEntries(ary, allowEmptyValue=false) {
export default Ember.Component.extend({
// Inputs
initialStr : null,
initialMap : null,
addActionLabel : 'formKeyValue.addAction',
keyLabel : 'formKeyValue.key.label',
valueLabel : 'formKeyValue.value.label',
keyPlaceholder : 'formKeyValue.key.placeholder',
valuePlaceholder : 'formKeyValue.value.placeholder',
allowEmptyValue : false,
addInitialEmptyRow : false,
allowMultilineValue : true,
ary : null,
initialStr: null,
initialMap: null,
addActionLabel: 'formKeyValue.addAction',
keyLabel: 'formKeyValue.key.label',
valueLabel: 'formKeyValue.value.label',
keyPlaceholder: 'formKeyValue.key.placeholder',
valuePlaceholder: 'formKeyValue.value.placeholder',
allowEmptyValue: false,
addInitialEmptyRow: false,
allowMultilineValue: true,
editing: true,
ary: null,
actions: {
add() {

View File

@ -1,4 +1,6 @@
<button class="btn-circle-text" {{action "add"}}><i class="icon icon-plus-circle"/> <span>{{t addActionLabel}}</span></button>
{{#if editing}}
<button class="btn-circle-text" {{action "add"}}><i class="icon icon-plus-circle"/> <span>{{t addActionLabel}}</span></button>
{{/if}}
{{#if ary.length}}
<table class="table fixed no-lines no-top-padding tight small">
@ -11,28 +13,46 @@
{{#each ary as |row|}}
<tr>
<td class="valign-top" data-title="Key">
{{input-paste pasted="pastedLabels" class="form-control input-sm key" type="text" value=row.key placeholder=keyPlaceholder}}
{{#if editing}}
{{input-paste pasted="pastedLabels" class="form-control input-sm key" type="text" value=row.key placeholder=keyPlaceholder}}
{{else}}
{{row.key}}
{{/if}}
</td>
<td class="valign-top text-center">
<p class="form-control-static input-sm">{{t 'formKeyValue.separator'}}</p>
{{#if editing}}
<p class="form-control-static input-sm">{{t 'formKeyValue.separator'}}</p>
{{/if}}
</td>
<td class="valign-top" data-title="Value">
{{#if allowMultilineValue}}
{{textarea-autogrow class="form-control input-sm value" value=row.value placeholder=valuePlaceholder}}
{{#if editing}}
{{#if allowMultilineValue}}
{{textarea-autogrow class="form-control input-sm value" value=row.value placeholder=valuePlaceholder}}
{{else}}
{{input class="form-control input-sm value" type="text" value=row.value placeholder=valuePlaceholder}}
{{/if}}
{{else}}
{{input class="form-control input-sm value" type="text" value=row.value placeholder=valuePlaceholder}}
{{row.value}}
{{/if}}
</td>
<td class="valign-top text-right">
<button class="btn btn-primary btn-sm" {{action "remove" row}}><i class="icon icon-minus"/><span class="sr-only">{{t 'generic.remove'}}</span></button>
{{#if editing}}
<button class="btn btn-primary btn-sm" {{action "remove" row}}><i class="icon icon-minus"/><span class="sr-only">{{t 'generic.remove'}}</span></button>
{{/if}}
</td>
</tr>
{{/each}}
</table>
<div class="text-muted" style="font-size: 12px; margin-bottom: 12px;">
{{t 'formKeyValue.protip'}}
</div>
{{#if editing}}
<div class="text-muted" style="font-size: 12px; margin-bottom: 12px;">
{{t 'formKeyValue.protip'}}
</div>
{{/if}}
{{else}}
{{#unless editing}}
<div class="form-control-static">{{t 'generic.none'}}</div>
{{/unless}}
{{/if}}

View File

@ -14,6 +14,7 @@ export default Ember.Component.extend(ManageLabels, ContainerChoices,{
initialLabels : null,
tagName : '',
editing: true,
init() {
this._super(...arguments);

View File

@ -4,12 +4,14 @@
</div>
<div class="col-sm-12 {{if isContainerNetwork 'col-md-3' 'col-md-8'}}">
{{new-select
classNames="form-control"
content=networkChoices
localizedLabel=true
value=instance.networkMode
}}
{{#input-or-display editable=editing value=instance.networkMode}}
{{new-select
classNames="form-control"
content=networkChoices
localizedLabel=true
value=instance.networkMode
}}
{{/input-or-display}}
</div>
{{#if isContainerNetwork}}
@ -17,14 +19,16 @@
<label class="form-control-static">{{t 'formNetwork.container.label'}}</label>
</div>
<div class="col-sm-12 col-md-3">
{{new-select
classNames="form-control"
content=containersOnRequestedHost
optionLabelPath="name"
optionValuePath="id"
optionGroupPath="group"
value=instance.networkContainerId
}}
{{#input-or-display editable=editing value=instance.networkContainerId}}
{{new-select
classNames="form-control"
content=containersOnRequestedHost
optionLabelPath="name"
optionValuePath="id"
optionGroupPath="group"
value=instance.networkContainerId
}}
{{/input-or-display}}
</div>
{{/if}}
</div>
@ -36,8 +40,10 @@
</div>
<div class="col-sm-12 col-md-8">
{{input type="text" value=requestedIp classNames="form-control" placeholder=(t 'formNetwork.requestedIp.placeholder')}}
<p class="help-block">{{t 'formNetwork.requestedIp.help'}}</p>
{{#input-or-display editable=editing value=requestedIp}}
{{input type="text" value=requestedIp classNames="form-control" placeholder=(t 'formNetwork.requestedIp.placeholder')}}
<p class="help-block">{{t 'formNetwork.requestedIp.help'}}</p>
{{/input-or-display}}
</div>
</div>
{{#if isService}}
@ -47,7 +53,9 @@
</div>
<div class="col-sm-12 col-md-8">
<label class="form-control-static">{{input type="checkbox" checked=service.retainIp}} {{t 'formNetwork.retainIp.reuse'}}</label>
{{#input-or-display editable=editing value=service.retainIp}}
<label class="form-control-static">{{input type="checkbox" checked=service.retainIp}} {{t 'formNetwork.retainIp.reuse'}}</label>
{{/input-or-display}}
</div>
</div>
{{/if}}
@ -59,14 +67,46 @@
</div>
<div class="col-sm-12 col-md-8">
<label class="form-control-static">{{input type="checkbox" checked=dnsDiscovery}} {{t 'formNetwork.dns.enable' appName=settings.appName}}</label>
{{#input-or-display editable=editing value=dnsDiscovery}}
<label class="form-control-static">{{input type="checkbox" checked=dnsDiscovery}} {{t 'formNetwork.dns.enable' appName=settings.appName}}</label>
{{/input-or-display}}
</div>
</div>
{{/if}}
{{/if}}
{{#unless isService}}
{{form-container-links initialLinks=instance.instanceLinks instance=instance allHosts=allHosts}}
{{#if editing}}
{{form-container-links initialLinks=instance.instanceLinks instance=instance allHosts=allHosts}}
{{else}}
<div class="row form-group">
<div class="col-sm-12 col-md-2 form-label">
<label>{{t 'formContainerLinks.label'}}</label>
</div>
<div class="col-sm-12 col-md-8">
{{#if instance.instanceLinks}}
<table class="grid fixed">
<thead>
<tr>
<th>{{t 'formNetwork.links.table.dest'}}</th>
<th>{{t 'formNetwork.links.table.as'}}</th>
</tr>
</thead>
<tbody>
{{#each-in instance.instanceLinks as |key value|}}
<tr>
<td class="force-wrap valign-top" data-title={{t 'formNetwork.links.table.data.dest'}}>{{key}}</td>
<td class="force-wrap valign-top" data-title={{t 'formNetwork.links.table.data.as'}}>{{value}}</td>
</tr>
{{/each-in}}
</tbody>
</table>
{{else}}
<div>{{t 'generic.none'}}</div>
{{/if}}
</div>
</div>
{{/if}}
{{/unless}}
<div class="row form-group">
@ -76,18 +116,22 @@
<div class="col-sm-12 col-md-8">
{{#if isService}}
<div class="radio small r-mt10">
<label>{{radio-button selection=hostname value="default"}} {{t 'formNetwork.hostname.dockerId'}}</label>
</div>
<div class="radio small r-mt10">
<label>{{radio-button selection=hostname value="override"}} {{t 'formNetwork.hostname.containerName'}}</label>
</div>
<div class="radio small">
<label>{{radio-button selection=hostname value="custom"}} {{t 'formNetwork.hostname.custom'}}:</label>
{{input type="text" value=instance.hostname classNames="form-control r-ml10 input-sm" safeStyle="display:inline; width: 200px;" placeholder=(t 'formNetwork.hostname.placeholder') disabled=(not-eq hostname "custom")}}
</div>
{{#input-or-display editable=editing value=hostname}}
<div class="radio small r-mt10">
<label>{{radio-button selection=hostname value="default"}} {{t 'formNetwork.hostname.dockerId'}}</label>
</div>
<div class="radio small r-mt10">
<label>{{radio-button selection=hostname value="override"}} {{t 'formNetwork.hostname.containerName'}}</label>
</div>
<div class="radio small">
<label>{{radio-button selection=hostname value="custom"}} {{t 'formNetwork.hostname.custom'}}:</label>
{{input type="text" value=instance.hostname classNames="form-control r-ml10 input-sm" safeStyle="display:inline; width: 200px;" placeholder=(t 'formNetwork.hostname.placeholder') disabled=(not-eq hostname "custom")}}
</div>
{{/input-or-display}}
{{else}}
{{input type="text" value=instance.hostname classNames="form-control" placeholder=(t 'formNetwork.hostname.placeholder')}}
{{#input-or-display editable=editing value=instance.hostname}}
{{input type="text" value=instance.hostname classNames="form-control" placeholder=(t 'formNetwork.hostname.placeholder')}}
{{/input-or-display}}
{{/if}}
</div>
</div>
@ -98,7 +142,9 @@
</div>
<div class="col-sm-12 col-md-8">
{{input type="text" value=instance.domainName classNames="form-control" placeholder=(t 'formNetwork.domainName.placeholder')}}
{{#input-or-display editable=editing value=instance.domainName}}
{{input type="text" value=instance.domainName classNames="form-control" placeholder=(t 'formNetwork.domainName.placeholder')}}
{{/input-or-display}}
</div>
</div>
@ -108,22 +154,41 @@
</div>
<div class="col-sm-12 col-md-8">
<div class="form-control-static">
<button class="btn-circle" {{action "addDnsResolver"}}><i class="icon icon-plus-circle"/></button>
</div>
{{#if dnsResolverArray.length}}
<table class="table fixed no-lines no-top-padding tight">
{{#each dnsResolverArray as |dns|}}
<tr>
<td>
{{input type="text" value=dns.value classNames="form-control dns-value input-sm" placeholder=(t 'formNetwork.resolvingServers.placeholder')}}
</td>
<td width="30" class="text-right">
<button class="btn btn-primary btn-sm" {{action "removeDnsResolver" dns}}><i class="icon icon-minus"/></button>
</td>
</tr>
{{/each}}
</table>
{{#if editing}}
<div class="form-control-static">
<button class="btn-circle" {{action "addDnsResolver"}}><i class="icon icon-plus-circle"/></button>
</div>
{{#if dnsResolverArray.length}}
<table class="table fixed no-lines no-top-padding tight">
{{#each dnsResolverArray as |dns|}}
<tr>
<td>
{{input type="text" value=dns.value classNames="form-control dns-value input-sm" placeholder=(t 'formNetwork.resolvingServers.placeholder')}}
</td>
<td width="30" class="text-right">
<button class="btn btn-primary btn-sm" {{action "removeDnsResolver" dns}}><i class="icon icon-minus"/></button>
</td>
</tr>
{{/each}}
</table>
{{/if}}
{{else}}
{{#if dnsResolverArray.length}}
<table class="table fixed no-lines no-top-padding tight r-mt10">
{{#each dnsResolverArray as |dns|}}
<tr>
<td>
{{dns.value}}
</td>
<td width="30" class="text-right">
&nbsp;
</td>
</tr>
{{/each}}
</table>
{{else}}
<div class="form-control-static">{{t 'generic.none'}}</div>
{{/if}}
{{/if}}
</div>
</div>
@ -134,22 +199,41 @@
</div>
<div class="col-sm-12 col-md-8">
<div class="form-control-static">
<button class="btn-circle" {{action "addDnsSearch"}}><i class="icon icon-plus-circle"/></button>
</div>
{{#if dnsSearchArray.length}}
<table class="table fixed no-lines no-top-padding tight">
{{#each dnsSearchArray as |dnsSearch|}}
<tr>
<td>
{{input type="text" value=dnsSearch.value classNames="form-control dns-search-value input-sm" placeholder=(t 'formNetwork.searchDomains.placeholder')}}
</td>
<td width="30" class="text-right">
<button class="btn btn-primary btn-sm" {{action "removeDnsSearch" dnsSearch}}><i class="icon icon-minus"/></button>
</td>
</tr>
{{/each}}
</table>
{{#if editing}}
<div class="form-control-static">
<button class="btn-circle" {{action "addDnsSearch"}}><i class="icon icon-plus-circle"/></button>
</div>
{{#if dnsSearchArray.length}}
<table class="table fixed no-lines no-top-padding tight">
{{#each dnsSearchArray as |dnsSearch|}}
<tr>
<td>
{{input type="text" value=dnsSearch.value classNames="form-control dns-search-value input-sm" placeholder=(t 'formNetwork.searchDomains.placeholder')}}
</td>
<td width="30" class="text-right">
<button class="btn btn-primary btn-sm" {{action "removeDnsSearch" dnsSearch}}><i class="icon icon-minus"/></button>
</td>
</tr>
{{/each}}
</table>
{{/if}}
{{else}}
{{#if dnsSearchArray.length}}
<table class="table fixed no-lines no-top-padding tight r-mt10">
{{#each dnsSearchArray as |dnsSearch|}}
<tr>
<td>
{{dnsSearch.value}}
</td>
<td width="30" class="text-right">
&nbsp;
</td>
</tr>
{{/each}}
</table>
{{else}}
<div class="form-control-static">{{t 'generic.none'}}</div>
{{/if}}
{{/if}}
</div>
</div>

View File

@ -105,6 +105,10 @@ export default Ember.Component.extend(ManageLabels, {
this.sendAction('setRequestedHost', hostId);
}.observes('requestedHostId'),
selectedChoice: Ember.computed('allHosts.@each.{id,name,state}', function() {
return this.get('hostChoices').findBy('id', this.get('initialHostId'));
}),
hostChoices: function() {
var list = this.get('allHosts').map((host) => {
var hostLabel = host.get('displayName');

View File

@ -1,47 +1,65 @@
<div class="form-group">
{{#if canRequestHost}}
<div class="radio">
<label class="form-control-static">{{radio-button selection=isRequestedHost value=true}}
{{#if isService}}
{{#if (eq isVm 'virtual machines')}}
{{format-html-message 'formScheduling.canRequestHost.vm'}}
{{else}}
{{format-html-message 'formScheduling.canRequestHost.containers'}}
{{/if~}}
{{if isRequestedHost ':'}}
{{else}}
Run on a specific host{{if isRequestedHost ':'}}
{{/if}}</label>
{{#if isRequestedHost}}
{{new-select
class="form-control"
content=hostChoices
value=requestedHostId
optionValuePath="id"
optionLabelPath="name"
disabled=(not isRequestedHost)
style="display: inline-block; width: auto;"
}}
{{/if}}
</div>
<div class="radio">
<label>{{radio-button selection=isRequestedHost value=false}}
{{#if isService}}
{{#if isGlobal}}
{{t 'formScheduling.autoRun'}}
{{else}}
{{#if editing}}
<div class="radio">
<label class="form-control-static">{{radio-button selection=isRequestedHost value=true}}
{{#if isService}}
{{#if (eq isVm 'virtual machines')}}
{{t 'formScheduling.autoPick.vm'}}
{{format-html-message 'formScheduling.canRequestHost.vm'}}
{{else}}
{{t 'formScheduling.autoPick.container'}}
{{format-html-message 'formScheduling.canRequestHost.containers'}}
{{/if~}}
{{if isRequestedHost ':'}}
{{else}}
Run on a specific host{{if isRequestedHost ':'}}
{{/if}}</label>
{{#if isRequestedHost}}
{{new-select
class="form-control"
content=hostChoices
value=requestedHostId
optionValuePath="id"
optionLabelPath="name"
disabled=(not isRequestedHost)
style="display: inline-block; width: auto;"
}}
{{/if}}
{{else}}
{{t 'formScheduling.autoPick.host'}}
{{/if}}
</label>
</div>
</div>
<div class="radio">
<label>{{radio-button selection=isRequestedHost value=false}}
{{#if isService}}
{{#if isGlobal}}
{{t 'formScheduling.autoRun'}}
{{else}}
{{#if (eq isVm 'virtual machines')}}
{{t 'formScheduling.autoPick.vm'}}
{{else}}
{{t 'formScheduling.autoPick.container'}}
{{/if~}}
{{/if}}
{{else}}
{{t 'formScheduling.autoPick.host'}}
{{/if}}
</label>
</div>
{{else}}
{{#if requestedHostId}}
<label class="form-control-static">
{{#if isService}}
{{#if (eq isVm 'virtual machines')}}
{{format-html-message 'formScheduling.canRequestHost.vm'}}
{{else}}
{{format-html-message 'formScheduling.canRequestHost.containers'}}
{{/if~}}
{{if isRequestedHost ':'}}
{{else}}
Run on a specific host{{if isRequestedHost ':'}}
{{/if}}
</label>
<span class="form-static-control">{{selectedChoice.name}}</span>
{{/if}}
{{/if}}
{{else}}
{{#if isService}}
{{#if isGlobal}}
@ -59,9 +77,11 @@
{{/if}}
{{#unless isRequestedHost}}
<div class="form-control-static">
<button class="btn-circle-text" {{action "addSchedulingRule"}}><i class="icon icon-plus-circle"/> <span>{{t 'formScheduling.addRule'}}</span></button>
</div>
{{#if editing}}
<div class="form-control-static">
<button class="btn-circle-text" {{action "addSchedulingRule"}}><i class="icon icon-plus-circle"/> <span>{{t 'formScheduling.addRule'}}</span></button>
</div>
{{/if}}
{{#if affinityLabelArray.length}}
<table class="table fixed no-lines no-top-padding tight small">
<thead>
@ -80,7 +100,12 @@
<tbody>
{{#each labelArray as |rule|}}
{{#if (eq rule.type "affinity")}}
{{scheduling-rule-row rule=rule allHosts=allHosts remove="removeSchedulingRule" isGlobal=isGlobal}}
{{scheduling-rule-row
editing=editing
rule=rule
allHosts=allHosts
remove="removeSchedulingRule"
isGlobal=isGlobal}}
{{/if}}
{{/each}}
</tbody>

View File

@ -273,4 +273,8 @@ export default Ember.Component.extend({
'splunk',
'syslog',
],
hasLogConfig: Ember.computed('instance.logConfig.config', function() {
return Ember.isEmpty(this.get('instance.logConfig.config'));
}),
});

View File

@ -3,18 +3,22 @@
<label class="form-control-static">{{t 'formSecurity.privileged.label'}}</label>
</div>
<div class="col-sm-12 col-md-3 form-label">
<div class="checkbox form-control-static text-left">
<label>{{input type="checkbox" checked=instance.privileged}} {{t 'formSecurity.privileged.checkbox'}}</label>
</div>
{{#input-or-display editable=editing value=instance.privileged}}
<div class="checkbox form-control-static text-left">
<label>{{input type="checkbox" checked=instance.privileged}} {{t 'formSecurity.privileged.checkbox'}}</label>
</div>
{{/input-or-display}}
</div>
<div class="col-sm-12 col-md-2 form-label">
<label class="form-control-static">{{t 'formSecurity.pidMode.label'}}</label>
</div>
<div class="col-sm-12 col-md-3 form-label">
<div class="checkbox form-control-static text-left">
<label>{{input type="checkbox" checked=pidHost}} {{t 'formSecurity.pidMode.checkbox'}}</label>
</div>
{{#input-or-display editable=editing value=pidHost}}
<div class="checkbox form-control-static text-left">
<label>{{input type="checkbox" checked=pidHost}} {{t 'formSecurity.pidMode.checkbox'}}</label>
</div>
{{/input-or-display}}
</div>
</div>
@ -23,20 +27,24 @@
<label class="form-control-static">{{t 'formSecurity.memoryLimit.label'}}</label>
</div>
<div class="col-sm-12 col-md-3">
<div class="input-group">
{{input type="number" min="1" step="1" value=memoryMb classNames="form-control" placeholder=(t 'formSecurity.memoryLimit.placeholder')}}
<div class="input-group-addon">{{t 'formSecurity.memoryLimit.mb'}}</div>
</div>
{{#input-or-display editable=editing value=memoryMb}}
<div class="input-group">
{{input type="number" min="1" step="1" value=memoryMb classNames="form-control" placeholder=(t 'formSecurity.memoryLimit.placeholder')}}
<div class="input-group-addon">{{t 'formSecurity.memoryLimit.mb'}}</div>
</div>
{{/input-or-display}}
</div>
<div class="col-sm-12 col-md-2 form-label">
<label class="form-control-static">{{t 'formSecurity.swapLimit.label'}}</label>
</div>
<div class="col-sm-12 col-md-3">
<div class="input-group">
{{input type="number" min="1" step="1" value=swapMb classNames="form-control" placeholder=(if memoryMb 'Requires Memory Limit' 'Unlimited') disabled=(not memoryMb)}}
<div class="input-group-addon">{{t 'formSecurity.swapLimit.mb'}}</div>
</div>
{{#input-or-display editable=editing value=swapMb}}
<div class="input-group">
{{input type="number" min="1" step="1" value=swapMb classNames="form-control" placeholder=(if memoryMb 'Requires Memory Limit' 'Unlimited') disabled=(not memoryMb)}}
<div class="input-group-addon">{{t 'formSecurity.swapLimit.mb'}}</div>
</div>
{{/input-or-display}}
</div>
</div>
@ -46,45 +54,70 @@
</div>
<div class="col-sm-12 col-md-3">
{{input type="text" value=instance.cpuSet classNames="form-control" placeholder=(t 'formSecurity.cpuPinning.placeholder')}}
{{#input-or-display editable=false value=instance.cpuSet}}
{{input type="text" value=instance.cpuSet classNames="form-control" placeholder=(t 'formSecurity.cpuPinning.placeholder')}}
{{/input-or-display}}
</div>
<div class="col-sm-12 col-md-2 form-label">
<label class="form-control-static">{{t 'formSecurity.shares.label'}}</label>
</div>
<div class="col-sm-12 col-md-3">
{{input type="number" value=instance.cpuShares step=128 min=0 classNames="form-control" placeholder=(t 'formSecurity.shares.placeholder')}}
{{#input-or-display editable=editing value=instance.cpuShares}}
{{input type="number" value=instance.cpuShares step=128 min=0 classNames="form-control" placeholder=(t 'formSecurity.shares.placeholder')}}
{{/input-or-display}}
</div>
</div>
<div class="row">
<div class="col-sm-12 col-md-2 form-label">
<label class="form-control-static">{{t 'formSecurity.capabilities.label'}}</label>
</div>
<div class="col-sm-12 col-md-4">
<select class="form-control select-cap-add" multiple="true" onchange={{action 'modifyCapabilities' 'capAdd' }}>
{{#each capabilityChoices as |choice|}}
<option value={{choice}} selected={{include instance.capAdd choice}}>{{choice}}</option>
{{/each}}
</select>
{{#if editing}}
<select class="form-control select-cap-add" multiple="true" onchange={{action 'modifyCapabilities' 'capAdd' }}>
{{#each capabilityChoices as |choice|}}
<option value={{choice}} selected={{include instance.capAdd choice}}>{{choice}}</option>
{{/each}}
</select>
{{else}}
{{#if instance.capAdd}}
{{#each instance.capAdd as |choice index|}}
{{if index ", "}} {{choice}}
{{/each}}
{{else}}
<div class="form-control-static">{{t 'generic.none'}}</div>
{{/if}}
{{/if}}
</div>
<div class="col-sm-12 col-md-4">
<select class="form-control select-cap-drop" multiple="true" onchange={{action 'modifyCapabilities' 'capDrop'}}>
{{#each capabilityChoices as |choice|}}
<option value={{choice}} selected={{include instance.capDrop choice}}>{{choice}}</option>
{{/each}}
</select>
{{#if editing}}
<select class="form-control select-cap-drop" multiple="true" onchange={{action 'modifyCapabilities' 'capDrop'}}>
{{#each capabilityChoices as |choice|}}
<option value={{choice}} selected={{include instance.capDrop choice}}>{{choice}}</option>
{{/each}}
</select>
{{else}}
{{#if instance.capDrop}}
{{#each instance.capDrop as |choice index|}}
{{if index ", "}} {{choice}}
{{/each}}
{{else}}
<div class="form-control-static">{{t 'generic.none'}}</div>
{{/if}}
{{/if}}
</div>
</div>
<div class="row">
<div class="col-sm-12 col-md-8 col-md-offset-2">
<span class="help-block">
{{t 'formSecurity.capabilities.helpBlock.text'}}
<a href="http://man7.org/linux/man-pages/man7/capabilities.7.html" target="_blank">{{t 'formSecurity.capabilities.helpBlock.link'}}</a>
</span>
{{#if editing}}
<div class="row">
<div class="col-sm-12 col-md-8 col-md-offset-2">
<span class="help-block">
{{t 'formSecurity.capabilities.helpBlock.text'}}
<a href="http://man7.org/linux/man-pages/man7/capabilities.7.html" target="_blank">{{t 'formSecurity.capabilities.helpBlock.link'}}</a>
</span>
</div>
</div>
</div>
{{/if}}
<div class="row form-group">
<div class="col-sm-12 col-md-2 form-label">
@ -92,40 +125,77 @@
</div>
<div class="col-sm-12 col-md-8">
<div class="form-control-static">
<button class="btn-circle" {{action "addDevice"}}><i class="icon icon-plus-circle"/></button>
</div>
{{#if devicesArray.length}}
<table class="table fixed no-lines no-top-padding tight small">
<tr class="text-muted">
<th>{{t 'formSecurity.deviceBinding.pathHost.label'}}</th>
<th width="30">&nbsp;</th>
<th>{{t 'formSecurity.deviceBinding.pathContainer.label'}}</th>
<th width="30">&nbsp;</th>
<th width="100">{{t 'formSecurity.deviceBinding.permissions.label'}}</th>
<th width="30">&nbsp;</th>
</tr>
{{#each devicesArray as |device|}}
<tr>
<td>
{{input class="form-control input-sm device-host" type="text" value=device.host placeholder=(t 'formSecurity.deviceBinding.pathHost.placeholder')}}
</td>
<td style="text-align: center">
<p class="form-control-static input-sm"><i class="icon icon-chevron-right"></i></p>
</td>
<td>
{{input class="form-control input-sm" type="text" value=device.container placeholder=(t 'formSecurity.deviceBinding.pathContainer.placeholder')}}
</td>
<td>&nbsp;</td>
<td>
{{device-permissions buttonClass="btn-sm" initialSelection=device.permissions changed=(action (mut device.permissions))}}
</td>
<td class="text-right">
<button class="btn btn-primary btn-sm" {{action "removeDevice" device}}><i class="icon icon-minus"/></button>
</td>
{{#if editing}}
<div class="form-control-static">
<button class="btn-circle" {{action "addDevice"}}><i class="icon icon-plus-circle"/></button>
</div>
{{#if devicesArray.length}}
<table class="table fixed no-lines no-top-padding tight small">
<tr class="text-muted">
<th>{{t 'formSecurity.deviceBinding.pathHost.label'}}</th>
<th width="30">&nbsp;</th>
<th>{{t 'formSecurity.deviceBinding.pathContainer.label'}}</th>
<th width="30">&nbsp;</th>
<th width="100">{{t 'formSecurity.deviceBinding.permissions.label'}}</th>
<th width="30">&nbsp;</th>
</tr>
{{/each}}
</table>
{{#each devicesArray as |device|}}
<tr>
<td>
{{input class="form-control input-sm device-host" type="text" value=device.host placeholder=(t 'formSecurity.deviceBinding.pathHost.placeholder')}}
</td>
<td style="text-align: center">
<p class="form-control-static input-sm"><i class="icon icon-chevron-right"></i></p>
</td>
<td>
{{input class="form-control input-sm" type="text" value=device.container placeholder=(t 'formSecurity.deviceBinding.pathContainer.placeholder')}}
</td>
<td>&nbsp;</td>
<td>
{{device-permissions buttonClass="btn-sm" initialSelection=device.permissions changed=(action (mut device.permissions))}}
</td>
<td class="text-right">
<button class="btn btn-primary btn-sm" {{action "removeDevice" device}}><i class="icon icon-minus"/></button>
</td>
</tr>
{{/each}}
</table>
{{/if}}
{{else}}
{{#if devicesArray.length}}
<table class="table fixed no-lines no-top-padding tight small">
<tr class="text-muted">
<th>{{t 'formSecurity.deviceBinding.pathHost.label'}}</th>
<th width="30">&nbsp;</th>
<th>{{t 'formSecurity.deviceBinding.pathContainer.label'}}</th>
<th width="30">&nbsp;</th>
<th width="100">{{t 'formSecurity.deviceBinding.permissions.label'}}</th>
<th width="30">&nbsp;</th>
</tr>
{{#each devicesArray as |device|}}
<tr>
<td>
{{device.host}}
</td>
<td style="text-align: center">
<p class="form-control-static input-sm r-pt10"><i class="icon icon-chevron-right"></i></p>
</td>
<td>
{{device.container}}
</td>
<td>&nbsp;</td>
<td>
{{device-permissions buttonClass="btn-sm" initialSelection=device.permissions changed=(action (mut device.permissions)) editing=editing}}
</td>
<td class="text-right">
&nbsp;
</td>
</tr>
{{/each}}
</table>
{{else}}
<div class="form-control-static">{{t 'generic.none'}}</div>
{{/if}}
{{/if}}
</div>
</div>
@ -136,17 +206,19 @@
</div>
<div class="col-sm-12 col-md-8">
<div class="input-group">
{{input type="text" value=instance.logConfig.driver classNames="form-control" placeholder=(t 'formSecurity.logDriver.placeholder')}}
<div class="input-group-btn">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><i class="icon icon-chevron-down"></i></button>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
{{#each logDriverChoices as |value|}}
<li><a {{action "setLogDriver" value}}>{{value}}</a></li>
{{/each}}
</ul>
{{#input-or-display editable=editing value=instance.logConfig.driver}}
<div class="input-group">
{{input type="text" value=instance.logConfig.driver classNames="form-control" placeholder=(t 'formSecurity.logDriver.placeholder')}}
<div class="input-group-btn">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><i class="icon icon-chevron-down"></i></button>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
{{#each logDriverChoices as |value|}}
<li><a {{action "setLogDriver" value}}>{{value}}</a></li>
{{/each}}
</ul>
</div>
</div>
</div>
{{/input-or-display}}
</div>
</div>
@ -162,6 +234,7 @@
addActionLabel="formSecurity.logConfig.addActionLabel"
keyPlaceholder="formSecurity.logConfig.keyPlaceholder"
valuePlaceholder="formSecurity.logConfig.valuePlaceholder"
editing=editing
}}
</div>
</div>

View File

@ -31,6 +31,7 @@ export default Ember.Component.extend({
linkName: 'containerStats',
single: true,
showGraphs: true,
showMultiStat: true,
renderSeconds: null,

View File

@ -1,6 +1,8 @@
<div class="container-multi-stat">
{{yield}}
</div>
{{#if showMultiStat}}
<div class="container-multi-stat">
{{yield}}
</div>
{{/if}}
{{#if showGraphs}}
<div class="row">
<div class="row-same-height row-full-height">

View File

@ -0,0 +1,9 @@
import Ember from 'ember';
export default Ember.Component.extend({
tagName: '',
value: null,
editable: true,
classesForInput: 'form-control',
classesForDisplay: 'form-control-static',
});

View File

@ -0,0 +1,9 @@
{{#if editable}}
{{yield}}
{{else}}
{{#if value}}
<div class={{classesForDisplay}}>{{value}}</div>
{{else}}
<div class={{classesForDisplay}}>{{t 'generic.none'}}</div>
{{/if}}
{{/if}}

View File

@ -136,7 +136,7 @@
<div class="section container-fluid" data-section="network">
{{form-networking
editing=editing
editing=true
instance=launchConfig
errors=networkingErrors
allHosts=allHosts
@ -148,12 +148,16 @@
</div>
<div class="section" data-section="security">
{{form-security instance=launchConfig errors=securityErrors}}
{{form-security instance=launchConfig errors=securityErrors editing=true}}
</div>
{{/if}}
<div class="section container-fluid" data-section="healthcheck">
{{form-healthcheck isService=isService healthCheck=launchConfig.healthCheck errors=healthCheckErrors}}
{{form-healthcheck
isService=isService
healthCheck=launchConfig.healthCheck
errors=healthCheckErrors
editing=true}}
</div>
<div class="section" data-section="labels">
@ -171,6 +175,7 @@
initialHostId=launchConfig.requestedHostId
initialLabels=launchConfig.labels
errors=schedulingErrors
editing=true
allHosts=allHosts
setLabels=(action 'setLabels' 'scheduling')
setGlobal=(action 'setGlobal')

View File

@ -181,6 +181,12 @@ export default Ember.Component.extend({
}
}.observes('isGlobal'),
getSuffixLabel: Ember.computed('suffix', function() {
let label = this.get('schedulingRuleSuffixChoices').findBy('value', this.get('suffix')).label;
label = label.split('.');
return label[label.length -1];
}),
schedulingRuleSuffixChoices: function() {
var out = [
{label: 'schedulingRuleRow.must', value: ''},

View File

@ -1,20 +1,28 @@
<td><div class="form-control-static input-sm">{{t 'schedulingRuleRow.theHost'}}</div></td>
<td>
{{new-select
classNames="form-control input-sm"
content=schedulingRuleSuffixChoices
localizedLabel=true
value=suffix
}}
{{#if editing}}
{{new-select
classNames="form-control input-sm"
content=schedulingRuleSuffixChoices
localizedLabel=true
value=suffix
}}
{{else}}
<div style="margin-top: 6px;">{{getSuffixLabel}}</div>
{{/if}}
</td>
<td><div class="form-control-static text-center input-sm">{{t 'schedulingRuleRow.haveA'}}</div></td>
<td>
{{new-select
classNames="form-control input-sm"
content=schedulingRuleKindChoices
localizedLabel=true
value=kind
}}
{{#if editing}}
{{new-select
classNames="form-control input-sm"
content=schedulingRuleKindChoices
localizedLabel=true
value=kind
}}
{{else}}
<div style="margin-top: 6px;">{{kind}}</div>
{{/if}}
</td>
<td>
{{#if (not (or (eq kind "service_name") (eq kind "container_name")))}}
@ -23,30 +31,38 @@
</td>
<td>
{{#if (eq kind "host_label")}}
<div class="input-group">
{{input type="text" class="form-control input-sm" value=userKey}}
<div class="input-group-btn">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><i class="icon icon-chevron-down"></i></button>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
{{#each hostLabelKeyChoices as |key|}}
<li><a {{action "setKey" key}}>{{key}}</a></li>
{{/each}}
</ul>
{{#if editing}}
<div class="input-group">
{{input type="text" class="form-control input-sm" value=userKey}}
<div class="input-group-btn">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><i class="icon icon-chevron-down"></i></button>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
{{#each hostLabelKeyChoices as |key|}}
<li><a {{action "setKey" key}}>{{key}}</a></li>
{{/each}}
</ul>
</div>
</div>
</div>
{{else}}
<div style="margin-top: 6px;">{{userKey}}</div>
{{/if}}
{{/if}}
{{#if (eq kind "container_label")}}
<div class="input-group">
{{input type="text" class="form-control input-sm" value=userKey}}
<div class="input-group-btn">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><i class="icon icon-chevron-down"></i></button>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
{{#each containerLabelKeyChoices as |key|}}
<li><a {{action "setKey" key}}>{{key}}</a></li>
{{/each}}
</ul>
{{#if editing}}
<div class="input-group">
{{input type="text" class="form-control input-sm" value=userKey}}
<div class="input-group-btn">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><i class="icon icon-chevron-down"></i></button>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
{{#each containerLabelKeyChoices as |key|}}
<li><a {{action "setKey" key}}>{{key}}</a></li>
{{/each}}
</ul>
</div>
</div>
</div>
{{else}}
<div style="margin-top: 6px;">{{userKey}}</div>
{{/if}}
{{/if}}
</td>
<td>
@ -56,66 +72,84 @@
</td>
<td>
{{#if (eq kind "host_label")}}
<div class="{{if hostLabelValueChoices 'input-group'}}">
{{input type="text" class="form-control input-sm" value=userValue}}
{{#if hostLabelValueChoices.length}}
<div class="input-group-btn">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><i class="icon icon-chevron-down"></i></button>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
{{#each hostLabelValueChoices as |value|}}
<li><a {{action "setValue" value}}>{{value}}</a></li>
{{/each}}
</ul>
</div>
{{/if}}
</div>
{{#if editing}}
<div class="{{if hostLabelValueChoices 'input-group'}}">
{{input type="text" class="form-control input-sm" value=userValue}}
{{#if hostLabelValueChoices.length}}
<div class="input-group-btn">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><i class="icon icon-chevron-down"></i></button>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
{{#each hostLabelValueChoices as |value|}}
<li><a {{action "setValue" value}}>{{value}}</a></li>
{{/each}}
</ul>
</div>
{{/if}}
</div>
{{else}}
<div style="margin-top: 6px;">{{userValue}}</div>
{{/if}}
{{/if}}
{{#if (eq kind "container_label")}}
<div class="{{if containerLabelValueChoices 'input-group'}}">
{{input type="text" class="form-control input-sm" value=userValue}}
{{#if containerLabelValueChoices.length}}
<div class="input-group-btn">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><i class="icon icon-chevron-down"></i></button>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
{{#each containerLabelValueChoices as |value|}}
<li><a {{action "setValue" value}}>{{value}}</a></li>
{{/each}}
</ul>
</div>
{{/if}}
</div>
{{#if editing}}
<div class="{{if containerLabelValueChoices 'input-group'}}">
{{input type="text" class="form-control input-sm" value=userValue}}
{{#if containerLabelValueChoices.length}}
<div class="input-group-btn">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><i class="icon icon-chevron-down"></i></button>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
{{#each containerLabelValueChoices as |value|}}
<li><a {{action "setValue" value}}>{{value}}</a></li>
{{/each}}
</ul>
</div>
{{/if}}
</div>
{{else}}
<div style="margin-top: 6px;">{{userValue}}</div>
{{/if}}
{{/if}}
{{#if (eq kind "service_name")}}
<div class="{{if serviceValueChoices 'input-group'}}">
{{input type="text" class="form-control input-sm" value=userValue}}
{{#if serviceValueChoices.length}}
<div class="input-group-btn">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><i class="icon icon-chevron-down"></i></button>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
{{#each serviceValueChoices as |value|}}
<li><a {{action "setValue" value}}>{{value}}</a></li>
{{/each}}
</ul>
</div>
{{/if}}
</div>
{{#if editing}}
<div class="{{if serviceValueChoices 'input-group'}}">
{{input type="text" class="form-control input-sm" value=userValue}}
{{#if serviceValueChoices.length}}
<div class="input-group-btn">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><i class="icon icon-chevron-down"></i></button>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
{{#each serviceValueChoices as |value|}}
<li><a {{action "setValue" value}}>{{value}}</a></li>
{{/each}}
</ul>
</div>
{{/if}}
</div>
{{else}}
<div style="margin-top: 6px;">{{userValue}}</div>
{{/if}}
{{/if}}
{{#if (eq kind "container_name")}}
<div class="{{if containerValueChoices 'input-group'}}">
{{input type="text" class="form-control input-sm" value=userValue}}
{{#if containerValueChoices.length}}
<div class="input-group-btn">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><i class="icon icon-chevron-down"></i></button>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
{{#each containerValueChoices as |value|}}
<li><a {{action "setValue" value}}>{{value}}</a></li>
{{/each}}
</ul>
</div>
{{/if}}
</div>
{{#if editing}}
<div class="{{if containerValueChoices 'input-group'}}">
{{input type="text" class="form-control input-sm" value=userValue}}
{{#if containerValueChoices.length}}
<div class="input-group-btn">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-expanded="false"><i class="icon icon-chevron-down"></i></button>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
{{#each containerValueChoices as |value|}}
<li><a {{action "setValue" value}}>{{value}}</a></li>
{{/each}}
</ul>
</div>
{{/if}}
</div>
{{else}}
<div style="margin-top: 6px;">{{userValue}}</div>
{{/if}}
{{/if}}
</td>
<td class="text-right">
<button class="btn btn-primary btn-sm" {{action "remove"}}><i class="icon icon-minus"/></button>
</td>
{{#if editing}}
<td class="text-right">
<button class="btn btn-primary btn-sm" {{action "remove"}}><i class="icon icon-minus"/></button>
</td>
{{/if}}

View File

@ -7,25 +7,6 @@
<span class="hand">{{snapshot.name}}</span> <i classs="icon icon-info"></i>
{{/tooltip-element}}
</td>
<td class="force-wrap">
{{#if (gt snapshot.backupCount 1)}}
{{#if snapshot.latestCompleteBackup}}
{{t 'snapshotSection.multiple' latestDate=(date-str snapshot.latestCompleteBackup.created)}}
{{else}}
{{badge-state model=snapshot.latestBackup}}
{{/if}}
{{else}}
{{#if (eq snapshot.backupCount 1)}}
{{#if snapshot.latestCompleteBackup}}
{{date-str snapshot.latestCompleteBackup.created}}
{{else}}
{{badge-state model=snapshot.latestBackup}}
{{/if}}
{{else}}
<span class="text-warning">{{t 'snapshotSection.none'}}</span>
{{/if}}
{{/if}}
</td>
<td class="actions">
{{action-menu model=snapshot}}
</td>

View File

@ -0,0 +1,82 @@
import Ember from 'ember';
import ThrottledResize from 'ui/mixins/throttled-resize';
const { get, set, computed } = Ember;
const SHIFT_DIFF = 3;
const PLOT_HEIGHT = 7;
export default Ember.Component.extend(ThrottledResize, {
tagName: 'div',
classNames: ['timeline-container'],
startDate: null,
endDate: null,
range: null,
init: function() {
this._super(...arguments);
if (!get(this, 'model')) {
set(this, 'classNames', []);
}
},
onResize: function() {
if (get(this, 'model')) {
this.plotSnapshots();
}
},
snapshots: computed('model', function() {
return this.plotSnapshots();
}),
plotSnapshots() {
let prevPlot = null;
let snapshots = get(this, 'model').sortBy('created');
let model = get(this, 'model');
let start = model[0].created;
let end = model[model.length - 1].created;
let range = moment(end).diff(start, 'seconds');
snapshots.forEach((snapshot) => {
let myDate = snapshot.created;
let fromStart = moment(myDate).diff(start, 'seconds');
let shift = (fromStart/range) * 100;
if (prevPlot !== null && prevPlot >= 0 && shift !== 100) {
if ((shift - prevPlot) <= SHIFT_DIFF) {
shift = prevPlot + SHIFT_DIFF;
}
}
prevPlot = shift;
set(snapshot, 'position', Ember.String.htmlSafe(`left: calc(${shift}% - ${PLOT_HEIGHT});`));
return snapshot;
});
prevPlot = null;
snapshots.reverse().forEach((snapshot) => {
let myDate = snapshot.created;
let fromStart = moment(myDate).diff(start, 'seconds');
let shift = (fromStart/range) * 100;
if (prevPlot !== null && shift >= 0) {
if (Math.abs(shift - prevPlot) <= SHIFT_DIFF) {
shift = Math.max(0, prevPlot - SHIFT_DIFF);
}
}
prevPlot = shift;
set(snapshot, 'position', Ember.String.htmlSafe(`left: calc(${shift}% - ${PLOT_HEIGHT}px);`));
return snapshot;
});
return snapshots.reverse();
},
});

View File

@ -0,0 +1,13 @@
{{#each snapshots as |snapshot|}}
<div class="snapshot {{snapshot.state}}" style={{snapshot.position}}>
{{#if (or (eq snapshot.state 'transitioning') (eq snapshot.state 'backingup'))}}
{{#tooltip-element type='tooltip-action-menu' model=snapshot tooltipTemplate='tooltip-snapshot-timeline' tagName="div" classNames='timeline-child'}}
<i class="icon {{snapshot.stateIcon}}"></i>
{{/tooltip-element}}
{{else}}
{{tooltip-element type='tooltip-action-menu' model=snapshot tooltipTemplate='tooltip-snapshot-timeline' tagName="div" classNames='timeline-child'}}
{{/if}}
</div>
{{else}}
<div class="text-muted">{{t 'snapshotTimeline.noData'}}</div>
{{/each}}

View File

@ -90,8 +90,7 @@
<tr>
<th width="125">{{t 'storagePoolSection.models.table.header.snapshotState'}}</th>
<th>{{t 'storagePoolSection.models.table.header.snapshotName'}}</th>
<th>{{t 'storagePoolSection.models.table.header.backedUp'}}</th>
<th width="75">&nbsp;</th>
<th width="70">&nbsp;</th>
</tr>
</thead>
<tbody>

View File

@ -9,13 +9,18 @@ export default Ember.Component.extend(Tooltip, StrippedName, {
model : Ember.computed.alias('tooltipService.tooltipOpts.model'),
actionsOpen : Ember.computed.alias('resourceActions.open'),
inTooltip : false,
layoutName: 'tooltip-action-menu',
setup: function() {
init: function() {
if (this.get('tooltipTemplate')) {
this.set('layoutName', this.get('tooltipTemplate'));
}
this._super(...arguments);
// Just so openChanged is ready to go, otherwise you have to chain on('init') on openChanged
// which because of the context menu click on container dot can cause some issues with checking
// flags and such. This was the least compliated way to ensure that openChanged would recognize changes
this.set('actionsOpen', false);
}.on('init'),
},
mouseEnter: function() {
this._super();

View File

@ -1,5 +0,0 @@
<div class="tooltip-content-inner tooltip-dot">
{{action-menu model=model showPrimary=false inTooltip=true class="pull-right tooltip-more-actions"}}
<div class="display-name">{{displayName}}</div>
<div class="display-ip">{{format-ip ip=model.displayIp}}</div>
</div>

View File

@ -2,6 +2,6 @@ import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.get('store').findAllUnremoved('backup');
return this.modelFor('container').container;
}
});

View File

@ -0,0 +1,7 @@
<div class="horizontal-form well">
{{form-command
instance=model
initialLabels=model.labels
editing=false
}}
</div>

View File

@ -0,0 +1,7 @@
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.modelFor('container').container;
}
});

View File

@ -0,0 +1,5 @@
<div class="horizontal-form well">
{{form-healthcheck
healthCheck=model.healthCheck
editing=false}}
</div>

View File

@ -2,6 +2,6 @@ import Ember from 'ember';
export default Ember.Route.extend({
redirect: function() {
this.replaceWith('container.labels');
this.replaceWith('container.ports');
}
});

View File

@ -0,0 +1,12 @@
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.get('store').findAll('host').then((hosts) => {
return {
hosts: hosts,
container: this.modelFor('container').container,
};
});
}
});

View File

@ -0,0 +1,8 @@
<div class="horizontal-form well">
{{form-networking
editing=false
instance=model.container
initialLabels=model.labels
allHosts=model.hosts
}}
</div>

View File

@ -0,0 +1,12 @@
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.get('store').findAll('host').then((hosts) => {
return {
hosts: hosts,
container: this.modelFor('container').container,
};
});
}
});

View File

@ -0,0 +1,8 @@
<div class="horizontal-form well">
{{form-scheduling
initialHostId=model.container.requestedHostId
initialLabels=model.container.labels
allHosts=model.hosts
editing=false
}}
</div>

View File

@ -0,0 +1,7 @@
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return this.modelFor('container').container;
}
});

View File

@ -0,0 +1,3 @@
<div class="horizontal-form well">
{{form-security instance=model editing=false}}
</div>

View File

@ -6,14 +6,6 @@
</div>
{{/power-select}}
{{#if model.primaryHost}}
<strong> {{t 'containersPage.containerPage.subtext.on'}} {{#link-to "host" model.primaryHost.id}}{{model.primaryHost.displayName}}{{/link-to}}</strong>
{{/if}}
{{#if model.primaryService}}
<strong> {{t 'containersPage.containerPage.subtext.in'}} {{#link-to "service" model.primaryService.environmentId model.primaryService.id}}{{model.primaryService.displayName}}{{/link-to}}</strong>
{{/if}}
<div class="pull-right">
{{action-menu model=model classNames="r-ml5 pull-right" size="sm"}}
{{header-state model=model classNames="pull-right"}}
@ -22,10 +14,19 @@
</section>
<section>
{{#info-multi-stats model=model linkName="containerStats" single=true}}
<div class="container-flex bordered">
<div class="col-flex">
<label>{{t 'containersPage.containerPage.infoMultiStats.host'}}</label>
<div class="row">
<div class="col-md-3 r-mb15">
{{#if model.description}}
<div>
<label class="block text-muted">{{t 'containersPage.containerPage.infoMultiStats.description'}}</label>
<div>{{model.description}}</div>
</div>
<hr>
{{/if}}
<div>
<label class="block text-muted">{{t 'containersPage.containerPage.infoMultiStats.host'}}</label>
{{#if model.primaryHost}}
{{#link-to "host" model.primaryHost.id}}{{model.primaryHost.displayName}}{{/link-to}}
{{copy-to-clipboard clipboardText=model.primaryHost.displayIp tooltipText=(t 'containersPage.containerPage.infoMultiStats.tooltip.host') size="small"}}
@ -33,28 +34,38 @@
<span class="text-muted">{{t 'generic.none'}}</span>
{{/if}}
</div>
<div class="col-flex">
<label>{{t 'containersPage.containerPage.infoMultiStats.ip'}}</label>
<hr>
<div>
<label class="block text-muted">{{t 'containersPage.containerPage.infoMultiStats.ip'}}</label>
{{format-ip ip=model.displayIp showCopy=true}}
</div>
<div class="col-flex">
<label>{{t 'containersPage.containerPage.infoMultiStats.docker'}}</label>
<hr>
<div>
<label class="block text-muted">{{t 'containersPage.containerPage.infoMultiStats.docker'}}</label>
{{#if model.displayExternalId}}
{{model.displayExternalId}} {{copy-to-clipboard clipboardText=model.externalId size='small'}}
{{else}}
<span class="text-muted">{{t 'generic.none'}}</span>
{{/if}}
</div>
</div>
<div class="container-flex bordered">
<div class="col-flex">
<label>{{t 'containersPage.containerPage.infoMultiStats.image'}}</label>
<hr>
<div>
<label class="block text-muted">{{t 'containersPage.containerPage.infoMultiStats.image'}}</label>
<span class="force-wrap">
{{model.displayImage}} {{copy-to-clipboard clipboardText=model.displayImage size='small'}}
</span>
</div>
<div class="col-flex">
<label>{{t 'containersPage.containerPage.infoMultiStats.command'}}</label>
<hr>
<div>
<label class="block text-muted">{{t 'containersPage.containerPage.infoMultiStats.command'}}</label>
<span class="force-wrap">
{{#if model.command}}
{{concat-str model.command}}
@ -63,8 +74,11 @@
{{/if}}
</span>
</div>
<div class="col-flex">
<label>{{t 'containersPage.containerPage.infoMultiStats.entryPoint'}}</label>
<hr>
<div>
<label class="block text-muted">{{t 'containersPage.containerPage.infoMultiStats.entryPoint'}}</label>
<span class="force-wrap">
{{#if model.entryPoint}}
{{concat-str model.entryPoint}}
@ -74,24 +88,26 @@
</span>
</div>
</div>
{{#if model.description}}
<div class="container-flex bordered">
<div class="col-flex description">
<label>{{t 'containersPage.containerPage.infoMultiStats.description'}} </label>
<span>{{model.description}}</span>
<div class="col-md-9">
<div class="row">
{{info-multi-stats model=model linkName="containerStats" single=true showMultiStat=false}}
</div>
<div class="row r-p15">
<ul class="nav nav-tabs nav-tabs-well shadowed">
{{#link-to "container.ports" tagName="li" href=false replace=true}}<a href="#"><i class="icon icon-network"></i> {{t 'containersPage.containerPage.navTabs.ports'}}</a>{{/link-to}}
{{#link-to "container.commands" tagName="li" href=false replace=true}}<a href="#"><i class="icon icon-tag"></i> {{t 'containersPage.containerPage.navTabs.command'}}</a>{{/link-to}}
{{#link-to "container.volumes" tagName="li" href=false replace=true}}<a href="#"><i class="icon icon-hdd"></i> {{t 'containersPage.containerPage.navTabs.volumes'}}</a>{{/link-to}}
{{#link-to "container.networking" tagName="li" href=false replace=true}}<a href="#"><i class="icon icon-hdd"></i> {{t 'containersPage.containerPage.navTabs.networking'}}</a>{{/link-to}}
{{#link-to "container.security" tagName="li" href=false replace=true}}<a href="#"><i class="icon icon-tag"></i> {{t 'containersPage.containerPage.navTabs.security'}}</a>{{/link-to}}
{{#link-to "container.healthcheck" tagName="li" href=false replace=true}}<a href="#"><i class="icon icon-tag"></i> {{t 'containersPage.containerPage.navTabs.healthCheck'}}</a>{{/link-to}}
{{#link-to "container.labels" tagName="li" href=false replace=true}}<a href="#"><i class="icon icon-tag"></i> {{t 'containersPage.containerPage.navTabs.labels'}}</a>{{/link-to}}
{{#link-to "container.scheduling" tagName="li" href=false replace=true}}<a href="#"><i class="icon icon-network"></i> {{t 'containersPage.containerPage.navTabs.scheduling'}}</a>{{/link-to}}
</ul>
<div class="table-flat well">
{{outlet}}
</div>
</div>
{{/if}}
{{/info-multi-stats}}
</section>
<section>
<ul class="nav nav-tabs nav-tabs-well shadowed">
{{#link-to "container.labels" tagName="li" href=false}}<a href="#"><i class="icon icon-tag"></i> {{t 'containersPage.containerPage.navTabs.labels'}}</a>{{/link-to}}
{{#link-to "container.volumes" tagName="li" href=false}}<a href="#"><i class="icon icon-hdd"></i> {{t 'containersPage.containerPage.navTabs.volumes'}}</a>{{/link-to}}
{{#link-to "container.ports" tagName="li" href=false}}<a href="#"><i class="icon icon-network"></i> {{t 'containersPage.containerPage.navTabs.ports'}}</a>{{/link-to}}
</ul>
<div class="table-flat well">
{{outlet}}
</div>
</div>
</section>

View File

@ -1,36 +1,26 @@
<table class="grid fixed">
<thead>
<tr>
<th width="90">{{t 'containersPage.containerPage.volumesTab.table.header.state'}}</th>
<th>{{t 'containersPage.containerPage.volumesTab.table.header.mount'}}</th>
<th>{{t 'containersPage.containerPage.volumesTab.table.header.shared'}}</th>
<th width="80">{{t 'containersPage.containerPage.volumesTab.table.header.writable'}}</th>
<th width="80">{{t 'containersPage.containerPage.volumesTab.table.header.name'}}</th>
<th width="175">{{t 'containersPage.containerPage.volumesTab.table.header.mount'}}</th>
<th>{{t 'containersPage.containerPage.volumesTab.table.header.snapshot'}}</th>
<th width="80">{{t 'containersPage.containerPage.volumesTab.table.header.actions'}}</th>
</tr>
</thead>
<tbody>
{{#each model.activeMounts as |mount|}}
<tr>
<td data-title={{t 'containersPage.containerPage.volumesTab.table.body.state'}}>
<span class="state {{mount.stateBackground}}">
{{mount.displayState}}
</span>
<td data-title={{t 'containersPage.containerPage.volumesTab.table.body.name'}}>
{{mount.ownedVolume.name}}
</td>
<td data-title={{t 'containersPage.containerPage.volumesTab.table.body.mount'}}>
{{mount.path}} {{copy-to-clipboard size='small' clipboardText=mount.path}}
{{mount.path}} {{if mount.isReadWrite '' '(ro)'}} {{copy-to-clipboard size='small' clipboardText=mount.path}}
</td>
<td data-title={{t 'containersPage.containerPage.volumesTab.table.body.shared'}}>
<ul class="list-unstyled">
{{#each mount.sharedContainers as |container|}}
<li>
{{#link-to "container" container.id}}{{container.displayName}}{{/link-to}}
</li>
{{else}}
<li class="text-muted">{{t 'containersPage.containerPage.volumesTab.table.body.noContainers'}}</li>
{{/each}}
</ul>
<td data-title={{t 'containersPage.containerPage.volumesTab.table.body.snapshot'}}>
{{snapshot-timeline model=mount.snapshotsAndBackups}}
</td>
<td data-title={{t 'containersPage.containerPage.volumesTab.table.body.writable'}}>
<i class="icon {{if mount.isReadWrite 'icon-check' 'icon-x text-muted'}}"></i>
<td data-title={{t 'containersPage.containerPage.volumesTab.table.body.actions'}}>
{{action-menu model=mount.ownedVolume}}
</td>
</tr>
{{else}}

View File

@ -7,6 +7,7 @@ import C from 'ui/utils/constants';
const defaultStateMap = {
'activating': {icon: 'icon icon-tag', color: 'text-info' },
'active': {icon: 'icon icon-circle-o', color: 'text-success'},
'backedup': {icon: 'icon icon-backup', color: 'text-success'},
'created': {icon: 'icon icon-tag', color: 'text-info' },
'creating': {icon: 'icon icon-tag', color: 'text-info' },
'deactivating': {icon: 'icon icon-adjust', color: 'text-info' },
@ -23,6 +24,7 @@ const defaultStateMap = {
'reinitializing': {icon: 'icon icon-alert', color: 'text-warning'},
'restoring': {icon: 'icon icon-medicalcross', color: 'text-info' },
'running': {icon: 'icon icon-circle-o', color: 'text-success'},
'snapshotted': {icon: 'icon icon-snapshot', color: 'text-warning'},
'started-once': {icon: 'icon icon-dot-circlefill',color: 'text-success'},
'starting': {icon: 'icon icon-adjust', color: 'text-info' },
'stopped': {icon: 'icon icon-circle', color: 'text-danger' },

View File

@ -2,21 +2,27 @@ import Ember from 'ember';
import Resource from 'ember-api-store/models/resource';
import C from 'ui/utils/constants';
const { getOwner } = Ember;
const { getOwner, computed } = Ember;
let _allMounts;
let _allContainers;
let _allVolumes;
let _allSnapshots;
var Mount = Resource.extend({
isReadWrite: Ember.computed.equal('permissions','rw'),
isReadOnly: Ember.computed.equal('permissions','ro'),
_allMounts : null,
_allContainers : null,
_allMounts: null,
_allContainers: null,
_allVolumes: null,
_allSnapshots: null,
reservedKeys: [
'_allMounts',
'_allContainers'
'_allContainers',
'_allVolumes',
'_allSnapshots',
],
init: function() {
@ -33,9 +39,20 @@ var Mount = Resource.extend({
_allContainers = store.allUnremoved('container');
}
if ( !_allVolumes ) {
_allVolumes = store.allUnremoved('volume');
}
if ( !_allSnapshots )
{
_allSnapshots = store.allUnremoved('snapshot');
}
this.setProperties({
'_allMounts' : _allMounts,
'_allContainers' : _allContainers,
'_allVolumes' : _allVolumes,
'_allSnapshots': _allSnapshots,
});
},
@ -85,12 +102,23 @@ var Mount = Resource.extend({
return out;
}.property('_allContainers.@each.instanceId', 'id'),
snapshotsAndBackups: computed('_allSnapshots.[]', function() {
let volumeId = this.get('volumeId');
return this.get('_allSnapshots').get('content').filterBy('volumeId', volumeId);
}),
ownedVolume: computed('_allVolumes.[]', function() {
return this.get('_allVolumes').findBy('id', this.get('volumeId'));
}),
});
Mount.reopenClass({
reset: function() {
_allMounts = null;
_allContainers = null;
_allMounts = null;
_allContainers = null;
_allVolumes = null;
_allSnapshots = null;
},
});

View File

@ -3,7 +3,6 @@ import Resource from 'ember-api-store/models/resource';
const { getOwner } = Ember;
// !! If you add a new one of these, you need to add it to reset() below too
var _allBackups;
var _allVolumes;
// !! If you add a new one of these, you need to add it to reset() below too
@ -11,11 +10,9 @@ var Snapshot = Resource.extend({
type: 'snapshot',
// !! If you add a new one of these, you need to add it to reset() below too
_allBackups: null,
_allVolumes: null,
reservedKeys: [
'_allBackups',
'_allVolumes',
],
@ -24,10 +21,6 @@ var Snapshot = Resource.extend({
// this.get('store') isn't set yet at init
var store = getOwner(this).lookup('store:main');
if ( !_allBackups )
{
_allBackups = store.allUnremoved('backup');
}
if ( !_allVolumes )
{
@ -35,7 +28,6 @@ var Snapshot = Resource.extend({
}
this.setProperties({
'_allBackups': _allBackups,
'_allVolumes': _allVolumes,
});
},
@ -58,14 +50,14 @@ var Snapshot = Resource.extend({
});
},
restoreFromBackup() {
this.get('volume').doAction('restorefrombackup', {
backupId: this.get('latestCompleteBackup.id'),
});
},
//restoreFromBackup() {
//this.get('volume').doAction('restorefrombackup', {
//backupId: this.get('latestCompleteBackup.id'),
//});
//},
deleteBackup() {
this.get('latestBackup').doAction('remove');
this.doAction('removebackup');
},
},
@ -73,44 +65,29 @@ var Snapshot = Resource.extend({
return this.get('_allVolumes').filterBy('id', this.get('volumeId'))[0];
}.property('_allVolumes.@each.volumeId','id'),
backups: function() {
return this.get('_allBackups').filterBy('snapshotId', this.get('id'));
}.property('_allBackups.@each.snapshotId','id'),
latestBackup: function() {
return this.get('backups').sortBy('id').pop();
}.property('backups.@each.id'),
latestCompleteBackup: function() {
return this.get('backups').filterBy('state','created').sortBy('id').pop();
}.property('backups.@each.{id,state}'),
backupCount: Ember.computed.alias('backups.length'),
hasBackups: Ember.computed.gte('backupCount',1),
backupEnabled: Ember.computed.equal('backupCount', 0),
hasBackups: Ember.computed.notEmpty('backupTargetId'),
backupEnabled: Ember.computed.empty('backupTargetId'),
availableActions: function() {
var a = this.get('actionLinks');
var volA = this.get('volume.actionLinks');
let created = this.get('state') === 'created';
let backedup = !!this.get('latestCompleteBackup');
let created = this.get('state') === 'snapshotted';
return [
{ label: 'action.remove', icon: 'icon icon-trash', action: 'promptDelete', enabled: !!a.remove, altAction: 'delete' },
{ divider: true },
{ label: 'action.revertToSnapshot', icon: 'icon icon-history', action: 'revertToSnapshot', enabled: created && volA && !!volA.reverttosnapshot },
{ label: 'action.restoreFromBackup', icon: 'icon icon-history', action: 'restoreFromBackup', enabled: created && volA && backedup && !!volA.restorefrombackup },
{ label: 'action.restoreFromBackup', icon: 'icon icon-history', action: 'restoreFromBackup', enabled: created && volA && this.get('hasBackups') && !!volA.restorefrombackup },
{ label: 'action.backup', icon: 'icon icon-hdd', action: 'backup', enabled: created && this.get('backupEnabled') },
{ label: 'action.deleteBackup', icon: 'icon icon-hdd', action: 'deleteBackup', enabled: this.get('hasBackups') },
{ label: 'action.viewInApi', icon: 'icon icon-external-link',action: 'goToApi', enabled: true },
];
}.property('actionLinks.remove','backupEnabled','hasBackups','latestCompleteBackup','volume.actionLinks.reverttosnapshot','state','volume.state'),
}.property('actionLinks.remove','backupEnabled','hasBackups','volume.actionLinks.reverttosnapshot','state','volume.state'),
});
Snapshot.reopenClass({
reset: function() {
_allBackups = null;
_allVolumes = null;
}
});

View File

@ -4,7 +4,6 @@ const { getOwner } = Ember;
// !! If you add a new one of these, you need to add it to reset() below too
var _allMounts;
var _allBackups;
var _allSnapshots;
// !! If you add a new one of these, you need to add it to reset() below too
@ -13,12 +12,10 @@ var Volume = Resource.extend({
// !! If you add a new one of these, you need to add it to reset() below too
_allMounts: null,
_allBackups: null,
_allSnapshots: null,
reservedKeys: [
'_allMounts',
'_allBackups',
'_allSnapshots',
],
@ -32,11 +29,6 @@ var Volume = Resource.extend({
_allMounts = store.allUnremoved('mount');
}
if ( !_allBackups )
{
_allBackups = store.allUnremoved('backup');
}
if ( !_allSnapshots )
{
_allSnapshots = store.allUnremoved('snapshot');
@ -44,7 +36,6 @@ var Volume = Resource.extend({
this.setProperties({
'_allMounts': _allMounts,
'_allBackups': _allBackups,
'_allSnapshots': _allSnapshots,
});
},
@ -93,15 +84,6 @@ var Volume = Resource.extend({
});
}.property('mounts.@each.state'),
backups: function() {
return this.get('_allBackups').filterBy('volumeId', this.get('id'));
}.property('_all_allBackups.@each.volumeId','id'),
activeBackups: function() {
var backups = this.get('backups')||[];
return backups.filterBy('state','created');
}.property('backups.@each.state'),
snapshots: function() {
return this.get('_allSnapshots').filterBy('volumeId', this.get('id'));
}.property('_allSnapshots.@each.volumeId','id'),
@ -110,7 +92,6 @@ var Volume = Resource.extend({
Volume.reopenClass({
reset: function() {
_allMounts = null;
_allBackups = null;
_allSnapshots = null;
},

View File

@ -17,6 +17,7 @@ Router.map(function() {
this.route('logout');
this.route('authenticated', {path: '/'}, function() {
this.route('dummy-dev', {path: '/dev'});
// Settings
this.route('settings', {resetNamespace: true}, function() {
this.route('projects', {path: '/env'}, function() {
@ -90,6 +91,11 @@ Router.map(function() {
this.route('ports');
this.route('volumes');
this.route('labels');
this.route('commands');
this.route('networking');
this.route('healthcheck');
this.route('scheduling');
this.route('security');
});
});
@ -116,7 +122,6 @@ Router.map(function() {
this.route('storagepools', {resetNamespace: true}, function() {
this.route('index', {path: '/'});
this.route('pools', {path: '/pools'});
this.route('backups', {path: '/backups'});
this.route('detail', {path: '/:storagepool_id'});
});
this.route('storagepools.new-volume', {path: '/add-volume', resetNamespace: true});

View File

@ -1,14 +0,0 @@
import Ember from 'ember';
import Sortable from 'ui/mixins/sortable';
export default Ember.Controller.extend(Sortable, {
sortableContent : Ember.computed.alias('model'),
sortBy: 'name',
sorts: {
state : ['stateSort','name','id'],
name : ['name','id'],
volume : ['volume.name','id'],
created : ['created','id'],
},
});

View File

@ -1,36 +0,0 @@
<table class="grid" style="margin-bottom: 0">
<thead>
<tr>
{{sortable-th sortable=this action="changeSort" name="state" width="125" label="generic.state"}}
{{sortable-th sortable=this action="changeSort" name="name" label="generic.name"}}
{{sortable-th sortable=this action="changeSort" name="volumeId" label="storagePoolsPage.volume"}}
{{sortable-th sortable=this action="changeSort" name="created" label="generic.created"}}
<th width="70">&nbsp;</th>
</tr>
</thead>
<tbody>
{{#each arranged as |target|}}
<tr>
<td class="state">
{{badge-state model=target}}
</td>
<td class="force-wrap">
{{target.name}}
</td>
<td class="force-wrap">
{{#if target.volume}}
{{target.volume.displayName}} ({{target.volumeId}})
{{else}}
{{t 'storagePoolsPage.orphaned'}}
{{/if}}
</td>
<td>
{{date-str target.created}}
</td>
<td class="actions wide">
{{action-menu model=target}}
</td>
</tr>
{{/each}}
</tbody>
</table>

View File

@ -6,8 +6,6 @@ export default Ember.Route.extend({
return Ember.RSVP.hash({
pools: store.findAllUnremoved('storagepool'),
mounts: store.findAllUnremoved('mounts'),
snapshots: store.findAllUnremoved('snapshots'),
backups: store.findAllUnremoved('backups'),
}).then((hash) => {
return hash.pools.filter((pool) => {
return !!pool.get('driverName');

View File

@ -2,10 +2,6 @@
<h1>{{t 'storagePoolsPage.header'}}</h1>
</section>
<section>
<ul class="nav nav-tabs nav-tabs-well">
{{#link-to "storagepools.pools" tagName="li" href=false}}<a href="#">{{t 'storagePoolsPage.nav.pools'}}</a>{{/link-to}}
{{#link-to "storagepools.backups" tagName="li" href=false}}<a href="#">{{t 'storagePoolsPage.nav.backups'}}</a>{{/link-to}}
</ul>
<div class="well nav-well">
{{outlet}}
</div>

View File

@ -62,6 +62,7 @@
@import "app/styles/components/multi-stats";
@import "app/styles/components/tooltip";
@import "app/styles/components/container-shell";
@import "app/styles/components/timeline";
//******************************************
// Pages

View File

@ -62,6 +62,7 @@
@import "app/styles/components/multi-stats";
@import "app/styles/components/tooltip";
@import "app/styles/components/container-shell";
@import "app/styles/components/timeline";
//******************************************
// Pages

View File

@ -0,0 +1,65 @@
$timeline-height: 15px;
@mixin timeline-dot {
border-radius: 50%;
border: 1px solid white;
height: $timeline-height;
position: absolute;
top: 0;
width: $timeline-height;
z-index: 2;
}
.timeline-container {
background-color: $lightGray;
height: $timeline-height;
margin: 0 auto;
position: relative;
width: calc(100% - #{$timeline-height});
&:before,
&:after {
background-color: $lightGray;
border-radius: 50%;
content: '';
display: inline-block;
height: $timeline-height;
position: absolute;
top: 0;
width: $timeline-height;
}
&:before {
left: calc( calc(#{$timeline-height}/2) * -1 );
}
&:after {
right: calc( calc(#{$timeline-height}/2) * -1 );
}
.timeline-child {
height: $timeline-height;
width: $timeline-height;
}
.snapshot {
@include timeline-dot;
background: $orangeDark;
&.backedup {
background: $navyTwoDark;
}
&:first-child {
left: -10px !important;
}
i.icon {
font-size: 11px;
left: 1px;
position: relative;
top: -3px;
}
}
}

View File

@ -373,6 +373,9 @@ TABLE.graphs {
.inline-block {
display : inline-block;
}
.block {
display: block;
}
.no-select {
-webkit-touch-callout : none;

View File

@ -14,7 +14,22 @@
}
@media (max-width: $screen-md-max) {
.nav-tabs {
LI {
margin-right: 2px;
A {
font-size: 13px;
padding: 10px;
.icon {
display: none;
}
}
}
}
HEADER NAV .navbar-nav > LI {
width: auto;
}
}
}

View File

@ -1,16 +1,18 @@
/*xs*/
@media (min-width: $screen-xs) { // 480px
@media (min-width: $screen-xs) {
// 480px
div.banner {
padding: 0 ;
padding: 0;
.banner-head {
display: block;
position: relative;
&::after {
display:none;
display: none;
}
}
.banner-content {
display: block;
margin-left: 0;
@ -23,10 +25,9 @@
}
}
/*small*/
@media (min-width: $screen-sm) {
.col-sm-height {
.col-sm-height {
display: table-cell;
float: none !important;
}
@ -43,7 +44,7 @@
position: absolute;
&::after {
display:initial;
display: initial;
}
}
@ -74,19 +75,24 @@
width: 20%;
margin: 0;
border-top: dotted 1px $lightGray;
&.count {
width: 25%;
}
&.stack-actions {
width: 11%;
}
&.stack-template {
width: 50%;
}
}
.header-left.name {
width: 70%;
}
.stack-actions {
text-align: center !important;
}
@ -94,85 +100,86 @@
/*responsive tables and nav 695-959*/
table,
thead,
tbody,
th,
td,
tr {
display: block;
}
table,
thead,
tbody,
th,
td,
tr {
display: block;
}
thead {
height: 0;
thead {
height: 0;
position: absolute;
top: -9999px;
left: -9999px;
& tr {
position: absolute;
top: -9999px;
left: -9999px;
& tr {
position: absolute;
top: -9999px;
left: -9999px;
}
}
}
tr {
tr {
border: 1px solid $table-border-color;
margin: 10px 0;
&.sm-noborder{
&.sm-noborder {
border-width: 0px;
}
}
td {
border: none;
border-bottom: 1px solid #eee;
position: relative;
padding-left: 50%;
white-space: normal;
text-align:left;
width: 100% !important;
border-right: none !important;
td {
border: none;
border-bottom: 1px solid #eee;
position: relative;
padding-left: 50%;
white-space: normal;
text-align: left;
width: 100% !important;
border-right: none !important;
& .spark-line {
width: 44px !important;
}
& .spark-line {
width: 44px !important;
}
}
td:before {
content: attr(data-title);
width: 45%;
margin-right: 10px;
white-space: nowrap;
text-align:left;
font-weight: bold;
}
td:before {
content: attr(data-title);
width: 45%;
margin-right: 10px;
white-space: nowrap;
text-align: left;
font-weight: bold;
}
.stack-section .grid td.state {
padding: 10px !important;
}
.stack-section .grid td.state {
padding: 10px !important;
}
.grid TD.actions {
position: static;
text-align: left;
}
position: static;
text-align: left;
}
.stack-section {
background: transparent !important;
}
.stack-section .grid TD, .stack-section .grid TH {
border-bottom: 1px dotted $table-border-color !important;
border-top: none;
text-align: left !important;
}
.stack-section {
background: transparent !important;
}
.grid > thead > tr > th,
.grid > thead > tr > td,
.grid > tbody > tr > th,
.grid > tbody > tr > td,
.grid > tfoot > tr > th,
.grid > tfoot > tr > td {
border-top: none;
}
}
.stack-section .grid TD, .stack-section .grid TH {
border-bottom: 1px dotted $table-border-color !important;
border-top: none;
text-align: left !important;
}
.grid > thead > tr > th,
.grid > thead > tr > td,
.grid > tbody > tr > th,
.grid > tbody > tr > td,
.grid > tfoot > tr > th,
.grid > tfoot > tr > td {
border-top: none;
}
}

View File

@ -21,6 +21,15 @@
animation: orbit 20s linear infinite; /* IE 10+, Fx 29+ */
}
.i-hate-spinners {
.orbit,
.loadfield,
.icon-spin {
animation: none;
-webkit-animation:: none;
}
}
.sun {
background : $yellowDark;
top : 110px;
@ -341,4 +350,4 @@
opacity: 1;
filter: alpha(opacity=100);
}
}
}

View File

@ -0,0 +1,5 @@
<div class="tooltip-content-inner tooltip-dot">
{{action-menu model=model showPrimary=false inTooltip=true class="pull-right tooltip-more-actions"}}
<div class="display-name">{{displayName}}</div>
<div class="display-ip">{{format-ip ip=model.displayIp}}</div>
</div>

View File

@ -0,0 +1,9 @@
<div class="tooltip-content-inner tooltip-dot">
{{action-menu model=model showPrimary=false inTooltip=true class="pull-right tooltip-more-actions"}}
<div class="display-name">{{displayName}}</div>
<div class="bottom-row">
<span class="pull-left">{{model.state}}</span>
<span class="pull-right r-pr20">{{format-date model.created}}</span>
</div>
</div>

View File

@ -132,7 +132,8 @@ var C = {
EXPANDED_STACKS : 'expandedStacks',
SORT_STACKS_BY : 'sortStacksBy',
THEME : 'theme',
LANGUAGE : 'language'
LANGUAGE : 'language',
I_HATE_SPINNERS: 'ihatespinners'
},
LANGUAGE: {

View File

@ -1,11 +0,0 @@
import { moduleFor, test } from 'ember-qunit';
moduleFor('route:storagepools/backups', 'Unit | Route | storagepools/backups', {
// Specify the other units that are required for this test.
// needs: ['controller:foo']
});
test('it exists', function(assert) {
let route = this.subject();
assert.ok(route);
});

View File

@ -408,6 +408,11 @@ containersPage:
labels: Labels
volumes: Volumes
ports: Ports
command: Command
networking: Networking
healthCheck: Health Check
scheduling: Scheduling
security: Security
portsTab:
table:
header:
@ -426,15 +431,21 @@ containersPage:
volumesTab:
table:
header:
name: Name
state: State
mount: Mount Point
shared: Shared With
writable: Writable
snapshot: Snapshot Timeline
actions: Actions
body:
name: 'Name:'
state: 'State:'
mount: 'Mount Point:'
shared: 'Shared With:'
writable: 'Writable:'
snapshot: 'Snapshot Timeline:'
actions: 'Actions:'
error:
data: 'Error:'
error: Error
@ -1009,7 +1020,7 @@ stacksPage:
label: Start services after creating
storagePoolsPage:
header: Storage
header: Storage Pools
volume: Volume Id
orphaned: Orphaned Backup
nav:
@ -1720,14 +1731,22 @@ formNameDescription:
placeholder: Description
formNetwork:
links:
table:
dest: Destination Container
as: As Name
data:
dest: 'Destination Container:'
as: 'As Name:'
networkMode:
label: Network
bridge: Bridge
container: container
host: Host
managed: Managed
none: None
container:
label: ontainer
label: container
requestedIp:
label: Requested IP
placeholder: e.g. 10.42.2.24
@ -1804,6 +1823,8 @@ formScheduling:
formSecurity:
key: Key
value: Value
logConfig:
addActionLabel: Add Option
keyPlaceholder: e.g. syslog-facility
@ -1849,7 +1870,7 @@ formSecurity:
label: Log Driver
placeholder: e.g. syslog
logOptions:
label: Log
label: Log Options
formServiceLinks:
addAction: Service Links
@ -2687,6 +2708,9 @@ siteAccess:
groups: Groups
organizations: Organizations
snapshotTimeline:
noData: No Snapshot Data
stackSection:
outputs: Outputs
description: Description

2
vendor/icons vendored

@ -1 +1 @@
Subproject commit 1d0df61b40b00f425ed65c6be7619fee7fd6f11b
Subproject commit 1f650aae61ed57c61c1d8defd0797f83f80ea9e8