Merge pull request #1095 from westlywright/new-cloud-dev

New cloud dev
This commit is contained in:
Vincent Fiduccia 2017-03-24 17:13:31 -07:00 committed by GitHub
commit a3d9fe1b6b
31 changed files with 443 additions and 250 deletions

View File

@ -1,5 +1,4 @@
import Ember from 'ember';
import C from 'ui/utils/constants';
export default Ember.Controller.extend({
tags: '',

View File

@ -2,10 +2,16 @@ import Ember from 'ember';
import C from 'ui/utils/constants';
export default Ember.Route.extend({
catalog: Ember.inject.service(),
modalService: Ember.inject.service('modal'),
catalog: Ember.inject.service(),
parentRoute: 'catalog-tab',
parentRoute: 'catalog-tab',
actions: {
cancel() {
this.get('modalService').toggleModal();
},
},
model: function(params/*, transition*/) {
var store = this.get('store');

View File

@ -0,0 +1,57 @@
import Ember from 'ember';
export default Ember.Component.extend({
access: Ember.inject.service(),
projects: Ember.inject.service(),
hostService: Ember.inject.service('host'),
driver: null,
hostId: null,
allowCustom: true,
allowOther: true,
forCatalog: true,
inModal: false,
goBack: null,
sortBy: ['name'],
sortedDrivers: Ember.computed.sort('model.availableDrivers','sortBy'),
didReceiveAttrs() {
if (!this.get('driver')) {
if (this.get('inModal')) {
this.set('driver', this.get('sortedDrivers.firstObject.name'));
} else {
this.set('driver', this.get('hostService.defaultDriver'));
}
}
},
actions: {
switchDriver(name) {
if (this.get('hostId')) {
this.set('hostId', null);
this.set('model.clonedModel', null);
}
this.set('driver', name);
},
},
driverObj: Ember.computed('driver', function() {
return this.get('model.availableDrivers').filterBy('name', this.get('driver'))[0];
}),
hasOther: Ember.computed('model.availableDrivers.@each.hasUi', function() {
return this.get('model.availableDrivers').filterBy('hasUi',false).length > 0;
}),
showPicker: Ember.computed('model.availableDrivers.length','allowOther','hasOther','allowCustom', function() {
return !this.get('projects.current.isWindows') && (
this.get('model.availableDrivers.length') +
(this.get('allowOther') && this.get('hasOther') ? 1 : 0) +
(this.get('allowCustom') ? 1 : 0)
) > 1;
}),
showManage: Ember.computed('access.admin','projects.current.isWindows', function() {
return !this.get('projects.current.isWindows') && this.get('access.admin');
}),
});

View File

@ -0,0 +1,46 @@
{{#if model.apiHostSet}}
<section class="pt-10">
{{#if showPicker}}
<div class="row nav nav-boxes checked-active">
{{#if (and allowCustom (not inModal))}}
<a {{action "switchDriver" "custom"}} alt="custom" class="col nav-box-item driver machine-driver custom {{if (eq driver 'custom') 'active'}}" href="#"></a>
{{/if}}
{{#each sortedDrivers as |choice|}}
{{#if choice.hasUi}}
<a {{action "switchDriver" choice.name}} alt={{choice.name}} class="col nav-box-item driver machine-driver {{choice.name}} {{if (eq choice.name driver) 'active'}}" href="#"></a>
{{/if}}
{{/each}}
{{#if (and allowOther hasOther)}}
<a {{action "switchDriver" "other"}} alt="other" class="col nav-box-item driver machine-driver other {{if (eq driver 'other') 'active'}}" href="#"></a>
{{/if}}
</div>
{{/if}}
{{#if (and access.admin (not forCatalog))}}
<p class="text-center small m-0">
{{#link-to "admin-tab.machine"}}{{t 'hostsPage.new.manageLink'}}{{/link-to}}
</p>
{{/if}}
</section>
{{#if driver}}
{{component (if (or (not driverObj) driverObj.hasUi) (concat "machine/driver-" driver) 'machine/driver-other')
cancel=(route-action 'cancel')
clonedModel=model.clonedModel
driver=(concat driver 'Config')
schemas=model.schemas
typeDocumentations=model.typeDocumentations
availableDrivers=model.availableDrivers
inModal=inModal
completed=(action completed)
goBack=goBack
}}
{{/if}}
{{else}}
<section>
<div>
{{host-settings saved="savedHost"}}
</div>
</section>
{{/if}}

View File

@ -1,7 +1,9 @@
<section class="horizontal-form">
<div class="container-fluid">
{{partial "host/add-common"}}
{{#unless inModal}}
{{partial "host/add-common"}}
{{/unless}}
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverAliyunecs.accountSection'}}</span>
@ -221,5 +223,5 @@
{{top-errors errors=errors}}
{{save-cancel save="save" cancel="cancel"}}
{{save-cancel save=driverSaveAction cancel="cancel"}}
</section>

View File

@ -227,7 +227,9 @@
<span>{{t 'machine.driverAmazon.instanceSection'}}</span>
</div>
{{partial "host/add-common"}}
{{#unless inModal}}
{{partial "host/add-common"}}
{{/unless}}
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverAmazon.instanceOptionsSection'}}</span>
@ -297,5 +299,5 @@
</div>
{{top-errors errors=errors}}
{{save-cancel save="save" cancel="cancel"}}
{{save-cancel save=driverSaveAction cancel="cancel"}}
</section>

View File

@ -1,6 +1,8 @@
<section class="horizontal-form">
<div class="container-fluid">
{{partial "host/add-common"}}
{{#unless inModal}}
{{partial "host/add-common"}}
{{/unless}}
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverAzure.placementSection'}}</span>
@ -198,5 +200,5 @@
</div>
{{top-errors errors=errors}}
{{save-cancel save="save" cancel="cancel"}}
{{save-cancel save=driverSaveAction cancel="cancel"}}
</section>

View File

@ -27,7 +27,9 @@
</form>
{{else}}
<div class="container-fluid">
{{partial "host/add-common"}}
{{#unless inModal}}
{{partial "host/add-common"}}
{{/unless}}
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverDigitalocean.regionSection'}}</span>
@ -109,6 +111,6 @@
</div>
{{top-errors errors=errors}}
{{save-cancel save="save" cancel="cancel"}}
{{save-cancel save=driverSaveAction cancel="cancel"}}
{{/if}}
</section>

View File

@ -131,7 +131,9 @@
<span>{{t 'machine.driverExoscale.instanceSection'}}</span>
</div>
{{partial "host/add-common"}}
{{#unless inModal}}
{{partial "host/add-common"}}
{{/unless}}
<div class="row inline-form">
<div class="col span-2 col-inline">
@ -169,5 +171,5 @@
</div>
{{top-errors errors=errors}}
{{save-cancel save="save" cancel="cancel"}}
{{save-cancel save=driverSaveAction cancel="cancel"}}
</section>

View File

@ -1,7 +1,9 @@
<section class="horizontal-form">
<div class="container-fluid">
{{partial "host/add-common"}}
{{#unless inModal}}
{{partial "host/add-common"}}
{{/unless}}
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverOther.driverSection'}}</span>
@ -39,5 +41,5 @@
</div>
{{top-errors errors=errors}}
{{save-cancel save="save" cancel="cancel"}}
{{save-cancel save=driverSaveAction cancel="cancel"}}
</section>

View File

@ -1,7 +1,9 @@
<form>
<section class="horizontal-form">
<div class="container-fluid">
{{partial "host/add-common"}}
{{#unless inModal}}
{{partial "host/add-common"}}
{{/unless}}
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverPacket.accountSection'}}</span>
@ -74,6 +76,6 @@
</div>
{{top-errors errors=errors}}
{{save-cancel save="save" cancel="cancel"}}
{{save-cancel save=driverSaveAction cancel="cancel"}}
</section>
</form>

View File

@ -2,7 +2,9 @@
<section class="horizontal-form">
<div class="container-fluid">
{{partial "host/add-common"}}
{{#unless inModal}}
{{partial "host/add-common"}}
{{/unless}}
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverRackspace.accountSection'}}</span>
@ -64,5 +66,5 @@
{{partial "host/add-options"}}
</div>
{{save-cancel save="save" cancel="cancel"}}
{{save-cancel save=driverSaveAction cancel="cancel"}}
</section>

View File

@ -67,7 +67,9 @@
<span>{{t 'machine.driverUbiquity.instanceSection'}}</span>
</div>
{{partial "host/add-common"}}
{{#unless inModal}}
{{partial "host/add-common"}}
{{/unless}}
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverUbiquity.regionSection'}}</span>
@ -113,5 +115,5 @@
</div>
{{top-errors errors=errors}}
{{save-cancel save="save" cancel="cancel"}}
{{save-cancel save=driverSaveAction cancel="cancel"}}
</section>

View File

@ -2,7 +2,9 @@
<section class="horizontal-form">
<div class="container-fluid">
{{partial "host/add-common"}}
{{#unless inModal}}
{{partial "host/add-common"}}
{{/unless}}
<div class="over-hr mt-20 mb-20">
<span>{{t 'machine.driverVsphere.accountSection'}}</span>
@ -131,5 +133,5 @@
{{partial "host/add-options"}}
</div>
{{save-cancel save="save" cancel="cancel"}}
{{save-cancel save=driverSaveAction cancel="cancel"}}
</section>

View File

@ -0,0 +1,32 @@
import Ember from 'ember';
import ModalBase from 'ui/mixins/modal-base';
export default Ember.Component.extend(ModalBase, {
modalService: Ember.inject.service('modal'),
hostService: Ember.inject.service('host'),
classNames: ['full-modal'],
loading: true,
model: null,
hostConfig: null,
goBack: null,
actions: {
completed(hostConfig) {
this.get('modalService.modalOpts.callee').send('completed', hostConfig);
Ember.run.next(() => {
this.get('modalService').toggleModal();
});
}
},
init() {
this._super(...arguments);
var hs = this.get('hostService');
hs.loadAllDrivers().then((drivers) => {
this.set('machineDrivers', drivers);
hs.getModel().then((hash) => {
this.set('model', hash);
this.set('loading', false);
});
});
}
});

View File

@ -0,0 +1,7 @@
{{#if loading}}
<div class="text-center">
<i class="icon icon-spinner icon-spin"></i> {{t 'generic.loading'}}
</div>
{{else}}
{{add-host model=model inModal=true completed=(action 'completed')}}
{{/if}}

View File

@ -0,0 +1,33 @@
import Ember from 'ember';
export default Ember.Component.extend({
modalService: Ember.inject.service('modal'),
hostConfig: null,
hostName: null,
value: null,
actions: {
launchHost() {
// we should reall not kill the previous driver if they edit, fix this in the future
if (this.get('hostConfig')) {
this.setProperties({
hostConfig: null,
hostName: null
});
}
this.get('modalService').toggleModal('modal-catalog-host', {
callee: this,
});
},
completed(value){
this.setProperties({
hostConfig: value, // probably use this when we are sending it back up on edit
value: JSON.stringify(value)
});
Object.keys(value).forEach((key) => {
if (key.indexOf('Config') >= 0) {
this.set('hostName', key.slice(0, key.indexOf('Config')).capitalize());
}
});
}
}
});

View File

@ -0,0 +1,5 @@
{{#if hostConfig}}
{{hostName}} <a href="#" {{action 'launchHost'}}>{{t 'generic.remove'}}</a>
{{else}}
<button {{action "launchHost"}} class="btn bg-primary">{{t 'schema.inputHost.label'}}</button>
{{/if}}

View File

@ -1,47 +1,11 @@
import Ember from 'ember';
export default Ember.Controller.extend({
access: Ember.inject.service(),
projects: Ember.inject.service(),
queryParams : ['backTo', 'driver', 'hostId'],
backTo : null,
driver : null,
hostId : null,
allowCustom : true,
allowOther : true,
actions: {
switchDriver(name) {
if (this.get('hostId')) {
this.set('hostId', null);
this.set('model.clonedModel', null);
}
this.set('driver', name);
},
},
driverObj: function() {
return this.get('model.availableDrivers').filterBy('name', this.get('driver'))[0];
}.property('driver'),
hasOther: function() {
return this.get('model.availableDrivers').filterBy('hasUi',false).length > 0;
}.property('model.availableDrivers.@each.hasUi'),
showPicker: function() {
return !this.get('projects.current.isWindows') && (
this.get('model.availableDrivers.length') +
(this.get('allowOther') && this.get('hasOther') ? 1 : 0) +
(this.get('allowCustom') ? 1 : 0)
) > 1;
}.property('model.availableDrivers.length','allowOther','hasOther','allowCustom'),
showManage: function() {
return !this.get('projects.current.isWindows') && this.get('access.admin');
}.property('access.admin','projects.current.isWindows'),
sortedDrivers: Ember.computed.sort('model.availableDrivers','sortBy'),
sortBy: ['name'],
completed() {}
}
});

View File

@ -1,25 +1,11 @@
import Ember from 'ember';
import C from 'ui/utils/constants';
import Util from 'ui/utils/util';
const { getOwner } = Ember;
function proxifyUrl(url, proxyBase) {
let parsed = Util.parseUrl(url);
if ( parsed.hostname.indexOf('.') === -1 || // No dot, local name like localhost
parsed.hostname.toLowerCase().match(/\.local$/) || // your-macbook.local
parsed.origin.toLowerCase() === window.location.origin // You are here
) {
return url;
} else {
return proxyBase + '/' + url;
}
}
export default Ember.Route.extend({
access : Ember.inject.service(),
projects : Ember.inject.service(),
settings : Ember.inject.service(),
host : Ember.inject.service(),
backTo : null,
defaultDriver: 'custom',
@ -77,142 +63,24 @@ export default Ember.Route.extend({
beforeModel(/*transition*/) {
this._super(...arguments);
let us = this.get('userStore');
let drivers = [];
var hs = this.get('host');
return us.find('machinedriver', null, {forceReload: true}).then((possible) => {
let promises = [];
possible.filterBy('state','active').forEach((driver) => {
let schemaName = driver.get('name') + 'Config';
promises.push(us.find('schema', schemaName).then(() => {
drivers.push(driver);
}).catch(() => {
return Ember.RSVP.resolve();
}));
});
return Ember.RSVP.all(promises);
}).then(() => {
return hs.loadAllDrivers().then((drivers) => {
this.set('machineDrivers', drivers);
});
},
model(params) {
this.set('backTo', params.backTo);
var hs = this.get('host');
let promises = {
reloadHost: this.get('userStore').find('schema','host', {forceReload: true}),
loadCustomUi: this.loadCustomUi(),
schemas: this.get('userStore').find('schema'),
typeDocumentations: this.get('userStore').findAll('typedocumentation')
};
if ( params.hostId )
{
promises.clonedModel = this.getHost(params.hostId);
}
if ( this.get('access.admin') ) {
let settings = this.get('settings');
promises.apiHostSet = settings.load(C.SETTING.API_HOST).then(() => {
return !!settings.get(C.SETTING.API_HOST);
});
} else {
promises.apiHostSet = Ember.RSVP.resolve(true);
}
return Ember.RSVP.hash(promises).then((hash) => {
hash.availableDrivers = this.get('machineDrivers');
if ( this.get('projects.current.isWindows') ) {
hash.availableDrivers = [];
}
let defaultDriver = this.get('defaultDriver');
let targetDriver = params.driver || this.get('lastDriver') || defaultDriver;
if ( ['custom','other'].indexOf(targetDriver) === -1 && hash.availableDrivers.filterBy('name', targetDriver).length === 0 )
{
targetDriver = defaultDriver;
}
if ( params.driver !== targetDriver )
{
this.transitionTo('hosts.new', {queryParams: {driver: targetDriver}});
}
else
{
return Ember.Object.create(hash);
}
});
},
// Loads the custom UI CSS/JS for drivers that have a uiUrl,
loadCustomUi() {
return new Ember.RSVP.Promise((resolve, reject) => {
let completed = 0, expected = 0;
let timer = null;
function loaded() {
completed++;
if ( completed === expected ) {
resolve();
clearTimeout(timer);
}
}
function errored(name) {
clearTimeout(timer);
reject({type: 'error', message: 'Error loading custom driver UI: ' + name});
}
// machineDrivers already contains only the active ones with a schema
this.get('machineDrivers').forEach((driver) => {
let id = 'driver-ui-js-' + driver.name;
if (driver.uiUrl && $(`#${id}`).length === 0 ) {
expected++;
let script = document.createElement('script');
script.onload = function() { loaded(driver.name); };
script.onerror = function() {errored(driver.name); };
script.src = proxifyUrl(driver.uiUrl, this.get('app.proxyEndpoint'));
script.id = id;
document.getElementsByTagName('BODY')[0].appendChild(script);
expected++;
let link = document.createElement('link');
link.rel = 'stylesheet';
link.id = id;
link.href = proxifyUrl(driver.uiUrl.replace(/\.js$/,'.css'), this.get('app.proxyEndpoint'));
link.onload = function() { loaded(driver.name); };
link.onerror = function() { errored(driver.name); };
document.getElementsByTagName('HEAD')[0].appendChild(link);
}
});
if ( expected === 0 ) {
resolve();
return hs.getModel(params).then((hash) => {
if (hash.transition) {
this.transitionTo('hosts.new', {queryParams: {driver: hash.driver}});
} else {
timer = setTimeout(function() {
reject({type: 'error', message: 'Timeout loading custom machine drivers'});
}, 10000);
return hash;
}
});
},
getHost(hostId) {
let store = this.get('store');
return store.find('host', hostId).then((host) => {
let hostOut = host.cloneForNew();
let src = host[`${host.driver}Config`];
if ( src ) {
src.type = `${host.driver}Config`;
let config = store.createRecord(src);
hostOut.set(`${host.driver}Config`, config);
}
return hostOut;
}).catch(() => {
return Ember.RSVP.reject({type: 'error', message: 'Failed to retrieve cloned model'}) ;
});
},
});

View File

@ -5,47 +5,4 @@
</h1>
</section>
{{#if model.apiHostSet}}
<section class="pt-10">
{{#if showPicker}}
<div class="row nav nav-boxes checked-active">
{{#if allowCustom}}
<a {{action "switchDriver" "custom"}} alt="custom" class="col nav-box-item driver machine-driver custom {{if (eq driver 'custom') 'active'}}" href="#"></a>
{{/if}}
{{#each sortedDrivers as |choice|}}
{{#if choice.hasUi}}
<a {{action "switchDriver" choice.name}} alt={{choice.name}} class="col nav-box-item driver machine-driver {{choice.name}} {{if (eq choice.name driver) 'active'}}" href="#"></a>
{{/if}}
{{/each}}
{{#if (and allowOther hasOther)}}
<a {{action "switchDriver" "other"}} alt="other" class="col nav-box-item driver machine-driver other {{if (eq driver 'other') 'active'}}" href="#"></a>
{{/if}}
</div>
{{/if}}
{{#if access.admin}}
<p class="text-center small m-0">
{{#link-to "admin-tab.machine"}}{{t 'hostsPage.new.manageLink'}}{{/link-to}}
</p>
{{/if}}
</section>
{{#if driver}}
{{component (if (or (not driverObj) driverObj.hasUi) (concat "machine/driver-" driver) 'machine/driver-other')
cancel=(route-action 'cancel')
goBack=(route-action 'goBack')
clonedModel=model.clonedModel
driver=(concat driver 'Config')
schemas=model.schemas
typeDocumentations=model.typeDocumentations
availableDrivers=model.availableDrivers
}}
{{/if}}
{{else}}
<section>
<div>
{{host-settings saved="savedHost"}}
</div>
</section>
{{/if}}
{{add-host model=model driver=driver hostId=hostId completed=(action 'completed') goBack=(route-action 'goBack')}}

4
app/ll/service.js Normal file
View File

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

View File

@ -19,6 +19,7 @@ export default Ember.Mixin.create(NewOrEdit, ManageLabels, {
multiTemplate : null,
clonedModel : null,
useHost : true,
hostConfig : null,
actions: {
addLabel: addAction('addLabel', '.key'),
@ -26,7 +27,13 @@ export default Ember.Mixin.create(NewOrEdit, ManageLabels, {
this.attrs.cancel();
},
goBack() {
this.attrs.goBack();
if (Ember.typeOf(this.attrs.goBack) === 'function') {
this.attrs.goBack();
}
},
passConfigBack(cb) {
this.sendAction('completed', this.get('model'));
cb(true);
},
setLabels(labels) {
let out = {};
@ -52,6 +59,14 @@ export default Ember.Mixin.create(NewOrEdit, ManageLabels, {
}
},
driverSaveAction: Ember.computed('inModal', function() {
if (this.get('inModal')) {
return 'passConfigBack';
} else {
return 'save';
}
}),
nameParts: function() {
let input = this.get('prefix')||'';
let count = this.get('count');

View File

@ -1,6 +1,5 @@
import Ember from 'ember';
import NewOrEdit from 'ui/mixins/new-or-edit';
import C from 'ui/utils/constants';
import {tagChoices, tagsToArray} from 'ui/models/stack';
export default Ember.Controller.extend(NewOrEdit, {

View File

@ -125,6 +125,9 @@ Router.map(function() {
this.route('add', {path: '/add/:cloud_id'});
});
this.route('new', {path: '/add'}, function() {
this.route('index', {path: '/'});
});
this.route('host', {path: '/:host_id', resetNamespace: true}, function() {
this.route('containers');

View File

@ -1,5 +1,4 @@
import Ember from 'ember';
import C from 'ui/utils/constants';
import { tagsToArray } from 'ui/models/stack';
import { headersWithHost as containerHeaders } from 'ui/components/container-table/component';

164
app/services/host.js Normal file
View File

@ -0,0 +1,164 @@
import Ember from 'ember';
import C from 'ui/utils/constants';
import Util from 'ui/utils/util';
function proxifyUrl(url, proxyBase) {
let parsed = Util.parseUrl(url);
if ( parsed.hostname.indexOf('.') === -1 || // No dot, local name like localhost
parsed.hostname.toLowerCase().match(/\.local$/) || // your-macbook.local
parsed.origin.toLowerCase() === window.location.origin // You are here
) {
return url;
} else {
return proxyBase + '/' + url;
}
}
export default Ember.Service.extend({
userStore: Ember.inject.service('user-store'),
access : Ember.inject.service(),
projects : Ember.inject.service(),
settings : Ember.inject.service(),
machineDrivers: null,
defaultDriver: 'custom',
loadAllDrivers() {
let us = this.get('userStore');
let drivers = [];
return new Ember.RSVP.Promise((resolve, reject) => {
us.find('machinedriver', null, {forceReload: true}).then((possible) => {
let promises = [];
possible.filterBy('state','active').forEach((driver) => {
let schemaName = driver.get('name') + 'Config';
promises.push(us.find('schema', schemaName).then(() => {
drivers.push(driver);
}).catch(() => {
reject();
}));
});
Ember.RSVP.all(promises);
}).then(() => {
this.set('machineDrivers', drivers);
resolve(drivers);
});
});
},
getHost(hostId) {
let store = this.get('store');
return store.find('host', hostId).then((host) => {
let hostOut = host.cloneForNew();
let src = host[`${host.driver}Config`];
if ( src ) {
src.type = `${host.driver}Config`;
let config = store.createRecord(src);
hostOut.set(`${host.driver}Config`, config);
}
return hostOut;
}).catch(() => {
return Ember.RSVP.reject({type: 'error', message: 'Failed to retrieve cloned model'}) ;
});
},
getModel(params=null) {
let promises = {
reloadHost: this.get('userStore').find('schema','host', {forceReload: true}),
loadCustomUi: this.loadCustomUi(),
schemas: this.get('userStore').find('schema'),
typeDocumentations: this.get('userStore').findAll('typedocumentation')
};
if (params && params.hostId )
{
promises.clonedModel = this.getHost(params.hostId);
}
if ( this.get('access.admin') ) {
let settings = this.get('settings');
promises.apiHostSet = settings.load(C.SETTING.API_HOST).then(() => {
return !!settings.get(C.SETTING.API_HOST);
});
} else {
promises.apiHostSet = Ember.RSVP.resolve(true);
}
return Ember.RSVP.hash(promises).then((hash) => {
hash.availableDrivers = this.get('machineDrivers');
if ( this.get('projects.current.isWindows') ) {
hash.availableDrivers = [];
}
let defaultDriver = this.get('defaultDriver');
let targetDriver = params && params.driver ? params.driver : defaultDriver;
if ( ['custom','other'].indexOf(targetDriver) === -1 && hash.availableDrivers.filterBy('name', targetDriver).length === 0 )
{
targetDriver = defaultDriver;
}
if (params && params.driver !== targetDriver )
{
return {transition: true, driver: targetDriver};
}
else
{
return Ember.Object.create(hash);
}
});
},
// Loads the custom UI CSS/JS for drivers that have a uiUrl,
loadCustomUi() {
return new Ember.RSVP.Promise((resolve, reject) => {
let completed = 0, expected = 0;
let timer = null;
function loaded() {
completed++;
if ( completed === expected ) {
resolve();
clearTimeout(timer);
}
}
function errored(name) {
clearTimeout(timer);
reject({type: 'error', message: 'Error loading custom driver UI: ' + name});
}
// machineDrivers already contains only the active ones with a schema
this.get('machineDrivers').forEach((driver) => {
let id = 'driver-ui-js-' + driver.name;
if (driver.uiUrl && $(`#${id}`).length === 0 ) {
expected++;
let script = document.createElement('script');
script.onload = function() { loaded(driver.name); };
script.onerror = function() {errored(driver.name); };
script.src = proxifyUrl(driver.uiUrl, this.get('app.proxyEndpoint'));
script.id = id;
document.getElementsByTagName('BODY')[0].appendChild(script);
expected++;
let link = document.createElement('link');
link.rel = 'stylesheet';
link.id = id;
link.href = proxifyUrl(driver.uiUrl.replace(/\.js$/,'.css'), this.get('app.proxyEndpoint'));
link.onload = function() { loaded(driver.name); };
link.onerror = function() { errored(driver.name); };
document.getElementsByTagName('HEAD')[0].appendChild(link);
}
});
if ( expected === 0 ) {
resolve();
} else {
timer = setTimeout(function() {
reject({type: 'error', message: 'Timeout loading custom machine drivers'});
}, 10000);
}
});
},
});

View File

@ -405,6 +405,7 @@ C.SUPPORTED_SCHEMA_INPUTS= [
'date',
'enum',
'float',
'host',
'int',
'multiline',
'password',

View File

@ -26,7 +26,7 @@
"dotenv": "^4.0.0",
"ember-api-store": "2.2.0",
"ember-browserify": "^1.0.1",
"ember-cli": "^2.9.1",
"ember-cli": "2.9.1",
"ember-cli-app-version": "^2.0.0",
"ember-cli-babel": "^5.1.7",
"ember-cli-clipboard": "0.4.1",
@ -60,7 +60,7 @@
"forever-agent": "^0.6.1",
"glob": "^5.0.3",
"http-proxy": "^1.11.1",
"liquid-fire": "0.26.4",
"liquid-fire": "0.27.1",
"loader.js": "^4.0.10",
"postcss-scss": "^0.4.0",
"semver": "^5.3.0",

View File

@ -0,0 +1,12 @@
import { moduleFor, test } from 'ember-qunit';
moduleFor('service:ll', 'Unit | Service | ll', {
// Specify the other units that are required for this test.
// needs: ['service:foo']
});
// Replace this with your real tests.
test('it exists', function(assert) {
let service = this.subject();
assert.ok(service);
});

View File

@ -3217,6 +3217,8 @@ schema:
prompt: Choose a Certificate...
inputEnum:
option: Choose an option...
inputHost:
label: Select Host
inputService:
prompt: Choose a Service...
inputSecret: