diff --git a/app/authenticated/project/controller.js b/app/authenticated/project/controller.js index 1e2b7d45b..0c2223df0 100644 --- a/app/authenticated/project/controller.js +++ b/app/authenticated/project/controller.js @@ -1,5 +1,4 @@ import Ember from 'ember'; -import C from 'ui/utils/constants'; export default Ember.Controller.extend({ tags: '', diff --git a/app/catalog-tab/launch/route.js b/app/catalog-tab/launch/route.js index 09fd38132..904fdab37 100644 --- a/app/catalog-tab/launch/route.js +++ b/app/catalog-tab/launch/route.js @@ -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'); diff --git a/app/components/add-host/component.js b/app/components/add-host/component.js new file mode 100644 index 000000000..d80db68b5 --- /dev/null +++ b/app/components/add-host/component.js @@ -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'); + }), +}); diff --git a/app/components/add-host/template.hbs b/app/components/add-host/template.hbs new file mode 100644 index 000000000..feb6b636a --- /dev/null +++ b/app/components/add-host/template.hbs @@ -0,0 +1,46 @@ +{{#if model.apiHostSet}} +
+ {{#if showPicker}} + + {{/if}} + {{#if (and access.admin (not forCatalog))}} +

+ {{#link-to "admin-tab.machine"}}{{t 'hostsPage.new.manageLink'}}{{/link-to}} +

+ {{/if}} +
+ + {{#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}} +
+
+ {{host-settings saved="savedHost"}} +
+
+{{/if}} diff --git a/app/components/machine/driver-aliyunecs/template.hbs b/app/components/machine/driver-aliyunecs/template.hbs index d6b16e8be..5e5fa05a0 100644 --- a/app/components/machine/driver-aliyunecs/template.hbs +++ b/app/components/machine/driver-aliyunecs/template.hbs @@ -1,7 +1,9 @@
- {{partial "host/add-common"}} + {{#unless inModal}} + {{partial "host/add-common"}} + {{/unless}}
{{t 'machine.driverAliyunecs.accountSection'}} @@ -221,5 +223,5 @@ {{top-errors errors=errors}} - {{save-cancel save="save" cancel="cancel"}} + {{save-cancel save=driverSaveAction cancel="cancel"}}
diff --git a/app/components/machine/driver-amazonec2/template.hbs b/app/components/machine/driver-amazonec2/template.hbs index 138da83f7..7483e9d08 100644 --- a/app/components/machine/driver-amazonec2/template.hbs +++ b/app/components/machine/driver-amazonec2/template.hbs @@ -227,7 +227,9 @@ {{t 'machine.driverAmazon.instanceSection'}} - {{partial "host/add-common"}} + {{#unless inModal}} + {{partial "host/add-common"}} + {{/unless}}
{{t 'machine.driverAmazon.instanceOptionsSection'}} @@ -297,5 +299,5 @@
{{top-errors errors=errors}} - {{save-cancel save="save" cancel="cancel"}} + {{save-cancel save=driverSaveAction cancel="cancel"}} diff --git a/app/components/machine/driver-azure/template.hbs b/app/components/machine/driver-azure/template.hbs index 42eb0ff06..1d9c3d177 100644 --- a/app/components/machine/driver-azure/template.hbs +++ b/app/components/machine/driver-azure/template.hbs @@ -1,6 +1,8 @@
- {{partial "host/add-common"}} + {{#unless inModal}} + {{partial "host/add-common"}} + {{/unless}}
{{t 'machine.driverAzure.placementSection'}} @@ -198,5 +200,5 @@
{{top-errors errors=errors}} - {{save-cancel save="save" cancel="cancel"}} + {{save-cancel save=driverSaveAction cancel="cancel"}}
diff --git a/app/components/machine/driver-digitalocean/template.hbs b/app/components/machine/driver-digitalocean/template.hbs index 79ec46e4e..fd220ef8b 100644 --- a/app/components/machine/driver-digitalocean/template.hbs +++ b/app/components/machine/driver-digitalocean/template.hbs @@ -27,7 +27,9 @@ {{else}}
- {{partial "host/add-common"}} + {{#unless inModal}} + {{partial "host/add-common"}} + {{/unless}}
{{t 'machine.driverDigitalocean.regionSection'}} @@ -109,6 +111,6 @@
{{top-errors errors=errors}} - {{save-cancel save="save" cancel="cancel"}} + {{save-cancel save=driverSaveAction cancel="cancel"}} {{/if}} diff --git a/app/components/machine/driver-exoscale/template.hbs b/app/components/machine/driver-exoscale/template.hbs index 97cd07d69..d78fd2734 100644 --- a/app/components/machine/driver-exoscale/template.hbs +++ b/app/components/machine/driver-exoscale/template.hbs @@ -131,7 +131,9 @@ {{t 'machine.driverExoscale.instanceSection'}}
- {{partial "host/add-common"}} + {{#unless inModal}} + {{partial "host/add-common"}} + {{/unless}}
@@ -169,5 +171,5 @@
{{top-errors errors=errors}} - {{save-cancel save="save" cancel="cancel"}} + {{save-cancel save=driverSaveAction cancel="cancel"}} diff --git a/app/components/machine/driver-other/template.hbs b/app/components/machine/driver-other/template.hbs index 7b82b919e..495534f0f 100644 --- a/app/components/machine/driver-other/template.hbs +++ b/app/components/machine/driver-other/template.hbs @@ -1,7 +1,9 @@
- {{partial "host/add-common"}} + {{#unless inModal}} + {{partial "host/add-common"}} + {{/unless}}
{{t 'machine.driverOther.driverSection'}} @@ -39,5 +41,5 @@
{{top-errors errors=errors}} - {{save-cancel save="save" cancel="cancel"}} + {{save-cancel save=driverSaveAction cancel="cancel"}}
diff --git a/app/components/machine/driver-packet/template.hbs b/app/components/machine/driver-packet/template.hbs index dba848d36..2eff8ffe7 100644 --- a/app/components/machine/driver-packet/template.hbs +++ b/app/components/machine/driver-packet/template.hbs @@ -1,7 +1,9 @@
- {{partial "host/add-common"}} + {{#unless inModal}} + {{partial "host/add-common"}} + {{/unless}}
{{t 'machine.driverPacket.accountSection'}} @@ -74,6 +76,6 @@
{{top-errors errors=errors}} - {{save-cancel save="save" cancel="cancel"}} + {{save-cancel save=driverSaveAction cancel="cancel"}}
diff --git a/app/components/machine/driver-rackspace/template.hbs b/app/components/machine/driver-rackspace/template.hbs index 0740560bd..46b3482a0 100644 --- a/app/components/machine/driver-rackspace/template.hbs +++ b/app/components/machine/driver-rackspace/template.hbs @@ -2,7 +2,9 @@
- {{partial "host/add-common"}} + {{#unless inModal}} + {{partial "host/add-common"}} + {{/unless}}
{{t 'machine.driverRackspace.accountSection'}} @@ -64,5 +66,5 @@ {{partial "host/add-options"}}
- {{save-cancel save="save" cancel="cancel"}} + {{save-cancel save=driverSaveAction cancel="cancel"}}
diff --git a/app/components/machine/driver-ubiquity/template.hbs b/app/components/machine/driver-ubiquity/template.hbs index d6a360696..ce60b7056 100644 --- a/app/components/machine/driver-ubiquity/template.hbs +++ b/app/components/machine/driver-ubiquity/template.hbs @@ -67,7 +67,9 @@ {{t 'machine.driverUbiquity.instanceSection'}}
- {{partial "host/add-common"}} + {{#unless inModal}} + {{partial "host/add-common"}} + {{/unless}}
{{t 'machine.driverUbiquity.regionSection'}} @@ -113,5 +115,5 @@
{{top-errors errors=errors}} - {{save-cancel save="save" cancel="cancel"}} + {{save-cancel save=driverSaveAction cancel="cancel"}} diff --git a/app/components/machine/driver-vmwarevsphere/template.hbs b/app/components/machine/driver-vmwarevsphere/template.hbs index d7dc9fe30..1e89b6b27 100644 --- a/app/components/machine/driver-vmwarevsphere/template.hbs +++ b/app/components/machine/driver-vmwarevsphere/template.hbs @@ -2,7 +2,9 @@
- {{partial "host/add-common"}} + {{#unless inModal}} + {{partial "host/add-common"}} + {{/unless}}
{{t 'machine.driverVsphere.accountSection'}} @@ -131,5 +133,5 @@ {{partial "host/add-options"}}
- {{save-cancel save="save" cancel="cancel"}} + {{save-cancel save=driverSaveAction cancel="cancel"}}
diff --git a/app/components/modal-catalog-host/component.js b/app/components/modal-catalog-host/component.js new file mode 100644 index 000000000..9bbab572d --- /dev/null +++ b/app/components/modal-catalog-host/component.js @@ -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); + }); + }); + } +}); diff --git a/app/components/modal-catalog-host/template.hbs b/app/components/modal-catalog-host/template.hbs new file mode 100644 index 000000000..60a87f3a9 --- /dev/null +++ b/app/components/modal-catalog-host/template.hbs @@ -0,0 +1,7 @@ +{{#if loading}} +
+ {{t 'generic.loading'}} +
+{{else}} + {{add-host model=model inModal=true completed=(action 'completed')}} +{{/if}} \ No newline at end of file diff --git a/app/components/schema/input-host/component.js b/app/components/schema/input-host/component.js new file mode 100644 index 000000000..4539edbcb --- /dev/null +++ b/app/components/schema/input-host/component.js @@ -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()); + } + }); + } + } +}); diff --git a/app/components/schema/input-host/template.hbs b/app/components/schema/input-host/template.hbs new file mode 100644 index 000000000..6db5d4973 --- /dev/null +++ b/app/components/schema/input-host/template.hbs @@ -0,0 +1,5 @@ +{{#if hostConfig}} + {{hostName}} {{t 'generic.remove'}} +{{else}} + +{{/if}} diff --git a/app/hosts/new/controller.js b/app/hosts/new/controller.js index ae6abeeec..f79ae2dfb 100644 --- a/app/hosts/new/controller.js +++ b/app/hosts/new/controller.js @@ -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() {} + } }); diff --git a/app/hosts/new/route.js b/app/hosts/new/route.js index a35be927b..5ceb830f0 100644 --- a/app/hosts/new/route.js +++ b/app/hosts/new/route.js @@ -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'}) ; - }); - }, }); diff --git a/app/hosts/new/template.hbs b/app/hosts/new/template.hbs index 46d6d391b..42a85fb06 100644 --- a/app/hosts/new/template.hbs +++ b/app/hosts/new/template.hbs @@ -5,47 +5,4 @@ -{{#if model.apiHostSet}} -
- {{#if showPicker}} - - {{/if}} - {{#if access.admin}} -

- {{#link-to "admin-tab.machine"}}{{t 'hostsPage.new.manageLink'}}{{/link-to}} -

- {{/if}} -
- - {{#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}} -
-
- {{host-settings saved="savedHost"}} -
-
-{{/if}} +{{add-host model=model driver=driver hostId=hostId completed=(action 'completed') goBack=(route-action 'goBack')}} \ No newline at end of file diff --git a/app/ll/service.js b/app/ll/service.js new file mode 100644 index 000000000..b9261c61d --- /dev/null +++ b/app/ll/service.js @@ -0,0 +1,4 @@ +import Ember from 'ember'; + +export default Ember.Service.extend({ +}); diff --git a/app/mixins/driver.js b/app/mixins/driver.js index 0f104f596..b32e54ceb 100644 --- a/app/mixins/driver.js +++ b/app/mixins/driver.js @@ -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'); diff --git a/app/new-stack/controller.js b/app/new-stack/controller.js index 7e1aaae0b..3a6f8cb19 100644 --- a/app/new-stack/controller.js +++ b/app/new-stack/controller.js @@ -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, { diff --git a/app/router.js b/app/router.js index dc2ea505a..f18843bd9 100644 --- a/app/router.js +++ b/app/router.js @@ -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'); diff --git a/app/scaling-groups/index/controller.js b/app/scaling-groups/index/controller.js index 15e6b23a2..81628351e 100644 --- a/app/scaling-groups/index/controller.js +++ b/app/scaling-groups/index/controller.js @@ -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'; diff --git a/app/services/host.js b/app/services/host.js new file mode 100644 index 000000000..b07174b67 --- /dev/null +++ b/app/services/host.js @@ -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); + } + }); + }, + +}); diff --git a/app/utils/constants.js b/app/utils/constants.js index ec59da71a..f122f3ca4 100644 --- a/app/utils/constants.js +++ b/app/utils/constants.js @@ -405,6 +405,7 @@ C.SUPPORTED_SCHEMA_INPUTS= [ 'date', 'enum', 'float', + 'host', 'int', 'multiline', 'password', diff --git a/package.json b/package.json index 3550e523f..da87c8bf8 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/tests/unit/ll/service-test.js b/tests/unit/ll/service-test.js new file mode 100644 index 000000000..2717ff060 --- /dev/null +++ b/tests/unit/ll/service-test.js @@ -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); +}); diff --git a/translations/en-us.yaml b/translations/en-us.yaml index 95db7077e..57caba930 100644 --- a/translations/en-us.yaml +++ b/translations/en-us.yaml @@ -3217,6 +3217,8 @@ schema: prompt: Choose a Certificate... inputEnum: option: Choose an option... + inputHost: + label: Select Host inputService: prompt: Choose a Service... inputSecret: