mirror of https://github.com/rancher/ui.git
Add new snapshot timeline (#800)
This commit is contained in:
parent
1c5980c571
commit
036d42aef7
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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"}}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Controller.extend({
|
||||
});
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Route.extend({
|
||||
model: function() {
|
||||
return [ ];
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
<section>
|
||||
<div class="well">
|
||||
</div>
|
||||
</section>
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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'),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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}}
|
||||
|
|
|
|||
|
|
@ -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'),
|
||||
|
|
|
|||
|
|
@ -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"> </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"> </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"> </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"> </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>
|
||||
|
|
|
|||
|
|
@ -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}}
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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}}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ export default Ember.Component.extend(ManageLabels, ContainerChoices,{
|
|||
initialLabels : null,
|
||||
|
||||
tagName : '',
|
||||
editing: true,
|
||||
|
||||
init() {
|
||||
this._super(...arguments);
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
||||
</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">
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</table>
|
||||
{{else}}
|
||||
<div class="form-control-static">{{t 'generic.none'}}</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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'));
|
||||
}),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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"> </th>
|
||||
<th>{{t 'formSecurity.deviceBinding.pathContainer.label'}}</th>
|
||||
<th width="30"> </th>
|
||||
<th width="100">{{t 'formSecurity.deviceBinding.permissions.label'}}</th>
|
||||
<th width="30"> </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> </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"> </th>
|
||||
<th>{{t 'formSecurity.deviceBinding.pathContainer.label'}}</th>
|
||||
<th width="30"> </th>
|
||||
<th width="100">{{t 'formSecurity.deviceBinding.permissions.label'}}</th>
|
||||
<th width="30"> </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> </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"> </th>
|
||||
<th>{{t 'formSecurity.deviceBinding.pathContainer.label'}}</th>
|
||||
<th width="30"> </th>
|
||||
<th width="100">{{t 'formSecurity.deviceBinding.permissions.label'}}</th>
|
||||
<th width="30"> </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> </td>
|
||||
<td>
|
||||
{{device-permissions buttonClass="btn-sm" initialSelection=device.permissions changed=(action (mut device.permissions)) editing=editing}}
|
||||
</td>
|
||||
<td class="text-right">
|
||||
|
||||
</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>
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ export default Ember.Component.extend({
|
|||
linkName: 'containerStats',
|
||||
single: true,
|
||||
showGraphs: true,
|
||||
showMultiStat: true,
|
||||
|
||||
renderSeconds: null,
|
||||
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
});
|
||||
|
|
@ -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}}
|
||||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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: ''},
|
||||
|
|
|
|||
|
|
@ -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}}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
},
|
||||
});
|
||||
|
|
@ -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}}
|
||||
|
|
@ -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"> </th>
|
||||
<th width="70"> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
<div class="horizontal-form well">
|
||||
{{form-command
|
||||
instance=model
|
||||
initialLabels=model.labels
|
||||
editing=false
|
||||
}}
|
||||
</div>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Route.extend({
|
||||
model: function() {
|
||||
return this.modelFor('container').container;
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<div class="horizontal-form well">
|
||||
{{form-healthcheck
|
||||
healthCheck=model.healthCheck
|
||||
editing=false}}
|
||||
</div>
|
||||
|
|
@ -2,6 +2,6 @@ import Ember from 'ember';
|
|||
|
||||
export default Ember.Route.extend({
|
||||
redirect: function() {
|
||||
this.replaceWith('container.labels');
|
||||
this.replaceWith('container.ports');
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<div class="horizontal-form well">
|
||||
{{form-networking
|
||||
editing=false
|
||||
instance=model.container
|
||||
initialLabels=model.labels
|
||||
allHosts=model.hosts
|
||||
}}
|
||||
</div>
|
||||
|
|
@ -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,
|
||||
};
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
@ -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>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import Ember from 'ember';
|
||||
|
||||
export default Ember.Route.extend({
|
||||
model: function() {
|
||||
return this.modelFor('container').container;
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<div class="horizontal-form well">
|
||||
{{form-security instance=model editing=false}}
|
||||
</div>
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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}}
|
||||
|
|
|
|||
|
|
@ -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' },
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
},
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -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});
|
||||
|
|
|
|||
|
|
@ -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'],
|
||||
},
|
||||
|
||||
});
|
||||
|
|
@ -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"> </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>
|
||||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -373,6 +373,9 @@ TABLE.graphs {
|
|||
.inline-block {
|
||||
display : inline-block;
|
||||
}
|
||||
.block {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.no-select {
|
||||
-webkit-touch-callout : none;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,21 @@
|
|||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
.grid TD.actions {
|
||||
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;
|
||||
}
|
||||
|
||||
.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;
|
||||
& .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;
|
||||
}
|
||||
|
||||
.stack-section .grid td.state {
|
||||
padding: 10px !important;
|
||||
}
|
||||
|
||||
.grid TD.actions {
|
||||
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;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
@ -132,7 +132,8 @@ var C = {
|
|||
EXPANDED_STACKS : 'expandedStacks',
|
||||
SORT_STACKS_BY : 'sortStacksBy',
|
||||
THEME : 'theme',
|
||||
LANGUAGE : 'language'
|
||||
LANGUAGE : 'language',
|
||||
I_HATE_SPINNERS: 'ihatespinners'
|
||||
},
|
||||
|
||||
LANGUAGE: {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 1d0df61b40b00f425ed65c6be7619fee7fd6f11b
|
||||
Subproject commit 1f650aae61ed57c61c1d8defd0797f83f80ea9e8
|
||||
Loading…
Reference in New Issue