Bug fixes

This commit is contained in:
Vincent Fiduccia 2015-12-17 09:57:53 -07:00
parent b9478560eb
commit 93224c3997
46 changed files with 366 additions and 354 deletions

View File

@ -2,6 +2,6 @@ import Ember from 'ember';
export default Ember.Route.extend({
beforeModel: function() {
this.transitionTo('admin-tab.accounts');
this.transitionTo('admin-tab.audit-logs');
}
});

View File

@ -1,5 +1,5 @@
<section class="header">
{{#link-to "admin-tab.processes" tagName="h1" href=false}}<a>Proccesses</a>{{/link-to}}
<h1>{{#link-to "admin-tab.processes"}}Proccesses:{{/link-to}}</h1>
{{model.processInstance.id}}
</section>

View File

@ -3,32 +3,30 @@ import C from 'ui/utils/constants';
import {denormalizeName} from 'ui/services/settings';
export default Ember.Route.extend({
endpoint: Ember.inject.service(),
settings: Ember.inject.service(),
model: function() {
beforeModel() {
var store = this.get('store');
return Ember.RSVP.all([
this.get('store').find('setting', denormalizeName(C.SETTING.API_HOST)),
this.get('store').find('setting', denormalizeName(C.SETTING.CATALOG_URL)),
this.get('store').find('setting', denormalizeName(C.SETTING.VM_ENABLED)),
]).then((/* response */) => {
return Ember.Object.create({
host: this.get('settings').get(C.SETTING.API_HOST),
catalog: this.get('settings').get(C.SETTING.CATALOG_URL),
vm: this.get('settings').get(C.SETTING.VM_ENABLED) || false,
});
store.find('setting', denormalizeName(C.SETTING.API_HOST)),
store.find('setting', denormalizeName(C.SETTING.CATALOG_URL)),
store.find('setting', denormalizeName(C.SETTING.VM_ENABLED)),
]);
},
model() {
var settings = this.get('settings');
return Ember.Object.create({
host: settings.get(C.SETTING.API_HOST),
catalog: settings.get(C.SETTING.CATALOG_URL),
vm: settings.get(C.SETTING.VM_ENABLED) || false,
});
},
setupController: function(controller, model) {
/*not sure we need this anymore except maybe to set error to null?*/
controller.set('model', model);
controller.set('error', null);
},
resetController: function(controller, isExiting /*, transition*/ ) {
resetController(controller, isExiting /*, transition*/ ) {
if (isExiting) {
controller.set('backToAdd', false);
controller.set('error', null);
}
}
});

View File

@ -18,26 +18,21 @@
</section>
<section class="well">
<h4>Virtual Machine</h4>
<h4>Virtual Machines</h4>
<hr>
<h5>Here you can enable access to virtual machines.</h5>
<div class="row r-mt20">
<div class="col-md-2">
<label>Virtual Machines Access</label>
<h5>Enable Virtual Machine support in the UI. Requires hosts that have <a href="https://en.wikipedia.org/wiki/Kernel-based_Virtual_Machine" target="_blank">KVM</a> loaded.</h5>
<div class="r-pt10">
<div class="radio small">
<label>
{{radio-button selection=model.vm value=true}}
Enabled
</label>
</div>
<div class="col-md-10">
<div class="radio small">
<label>
{{radio-button selection=model.vm value=true}}
Enable
</label>
</div>
<div class="radio small">
<label>
{{radio-button selection=model.vm value=false}}
Disable
</label>
</div>
<div class="radio small">
<label>
{{radio-button selection=model.vm value=false}}
Disabled
</label>
</div>
</div>
</section>

View File

@ -1,7 +1,7 @@
import Ember from 'ember';
export default Ember.Controller.extend({
queryParams: ['category', 'catalogid'],
queryParams: ['category', 'catalogId'],
category: 'all',
catalogid: 'library'
catalogId: 'all'
});

View File

@ -4,7 +4,12 @@ export default Ember.Controller.extend({
application: Ember.inject.controller(),
catalogController: Ember.inject.controller('applications-tab.catalog'),
category: Ember.computed.alias('catalogController.category'),
selectedCatalog: Ember.computed.alias('catalogController.catalogid'),
selectedCatalog: Ember.computed.alias('catalogController.catalogId'),
categories: Ember.computed.alias('model.categories'),
catalogIds: Ember.computed.alias('model.catalogIds'),
// > 2 because 'all' is one of them.
showCatalogDropdown: Ember.computed.gt('catalogIds.length',2),
search: '',
actions: {
@ -17,10 +22,6 @@ export default Ember.Controller.extend({
}
},
categories: Ember.computed.alias('model.categories'),
catalogIds: Ember.computed.alias('model.catalogIds'),
arrangedContent: function() {
var search = this.get('search').toUpperCase();
var result = [];

View File

@ -3,18 +3,20 @@
Catalog
</h1>
<div class="btn-group pull-right left-divider">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Catalog: <span class="text-capitalize">{{selectedCatalog}}</span> <i class="icon icon-chevron-down"></i></button>
<ul class="dropdown-menu dropdown-menu-right">
{{#each catalogIds as |catalog|}}
<li>
{{#link-to "applications-tab.catalog" (query-params catalogid=catalog)}}
<span class="text-capitalize">{{catalog}}</span>
{{/link-to}}
</li>
{{/each}}
</ul>
</div>
{{#if showCatalogDropdown}}
<div class="btn-group pull-right left-divider">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Catalog: <span class="text-capitalize">{{selectedCatalog}}</span> <i class="icon icon-chevron-down"></i></button>
<ul class="dropdown-menu dropdown-menu-right">
{{#each catalogIds as |catalog|}}
<li>
{{#link-to "applications-tab.catalog" (query-params catalogId=catalog)}}
<span class="text-capitalize">{{catalog}}</span>
{{/link-to}}
</li>
{{/each}}
</ul>
</div>
{{/if}}
<div class="btn-group pull-right left-divider">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Category: <span class="text-capitalize">{{category}}</span> <i class="icon icon-chevron-down"></i></button>
@ -38,7 +40,12 @@
<section class="r-plr15">
{{#each arrangedContent as |catalogItem|}}
<div class="container-catalog text-center">
<h5>{{catalogItem.name}}</h5>
<h5>
{{catalogItem.name}}
{{#if showCatalogDropdown}}
<span class="small">in <span class="text-capitalize">{{catalogItem.catalogId}}</span></span>
{{/if}}
</h5>
<div class="catalog-icon">
<img src="{{catalogItem.links.icon}}"/>
</div>

View File

@ -17,7 +17,7 @@ export default Ember.Route.extend({
category: {
refreshModel: true
},
catalogid: {
catalogId: {
refreshModel: true
}
},
@ -40,13 +40,13 @@ export default Ember.Route.extend({
var cache = this.get('cache');
// If the catalogIds dont match we need to go get the other catalog from the store since we do not cache all catalogs
if ( cache && cache.catalogId === params.catalogid)
if ( cache && cache.catalogId === params.catalogId)
{
return filter(cache, params.category, this.get('catalogIds'));
}
if (params.catalogid) {
this.controllerFor('applications-tab.catalog.index').set('selectedCatalog', params.catalogid);
if (params.catalogId) {
this.controllerFor('applications-tab.catalog.index').set('selectedCatalog', params.catalogId);
}
var version = this.get('settings.rancherVersion');
@ -54,8 +54,8 @@ export default Ember.Route.extend({
'category_ne': 'system',
};
if (params.catalogid !== 'all') {
qp['catalogId'] = params.catalogid;
if (params.catalogId !== 'all') {
qp['catalogId'] = params.catalogId;
}
if ( version )
@ -66,7 +66,7 @@ export default Ember.Route.extend({
var url = addQueryParams(this.get('app.catalogEndpoint')+'/templates', qp);
return this.get('store').request({url: url}).then((response) => {
response.catalogId = params.catalogid;
response.catalogId = params.catalogId;
this.set('cache', response);
return filter(response, params.category, this.get('catalogIds'));
});
@ -77,7 +77,6 @@ export default Ember.Route.extend({
var out = Ember.Object.create({
categories: uniqKeys(data, 'category'),
catalogIds: catalogIds,
});
if ( category === 'all' ) {
@ -89,4 +88,12 @@ export default Ember.Route.extend({
return out;
}
},
resetController: function (controller, isExiting/*, transition*/) {
if (isExiting)
{
controller.set('category', 'all');
controller.set('catalogId', 'all');
}
}
});

View File

@ -3,7 +3,7 @@ import Ember from 'ember';
export default Ember.Controller.extend({
actions: {
changeCertificate(cert) {
this.get('application').transitionToRoute('certificate.detail', cert.get('id'));
this.transitionToRoute('certificates.detail', cert.get('id'));
},
},
});

View File

@ -1,19 +1,23 @@
<section class="header">
<h1 class="right-divider">
{{#link-to "certificates" tagName="h1" href=false}}<a>Certificates</a>{{/link-to}}
{{#power-select options=model.allCertificates selected=model.certificate onchange=(action "changeCertificate") searchField="displayName" as |obj|}}
<div class="clip"><i class="{{obj.stateIcon}} {{obj.stateColor}}" tooltip="{{obj.displayState}}" data-placement="left"></i> {{obj.displayName}}</div>
{{/power-select}}
</h1>
<h1>{{#link-to "certificates"}}Certificate:{{/link-to}}</h1>
{{#power-select options=model.allCertificates selected=model.certificate onchange=(action "changeCertificate") searchField="displayName" as |obj|}}
<div class="clip"><i class="{{obj.stateIcon}} {{obj.stateColor}}" tooltip="{{obj.displayState}}" data-placement="left"></i> {{obj.displayName}}</div>
{{/power-select}}
{{action-menu model=model.certificate size="sm"}}
</section>
<section>
{{partial "description"}}
{{#if model.certificate.description}}
<section>
<div class="well description">
<label>Description</label>
<p>{{model.certificate.description}}</p>
</div>
</section>
{{/if}}
<section>
<div class="row">
<div class="row-same-height row-full-height">
<div class="col-sm-12 col-md-6 col-md-height col-md-full-height col-top" style="margin-bottom: 20px;">

View File

@ -1,6 +1,6 @@
<h4>Catalog</h4>
<hr>
<h5>You can add and remove catalogs here. When adding ensure you give your catalog a name and git url. The correct format of git urls can be found <a href="https://git-scm.com/docs/git-clone#_git_urls_a_id_urls_a" target="_blank">here</a>.</h5>
<h5>The catalog can retrieve templates from multiple sources. Each one needs a unique name and any URL that <code>git clone</code> can handle (see <a href="https://git-scm.com/docs/git-clone#_git_urls_a_id_urls_a" target="_blank">docs</a> for more info).</h5>
<div class="">
{{form-key-value
nameLabel="Catalog URL"

View File

@ -0,0 +1,28 @@
import Ember from 'ember';
export default Ember.Component.extend({
dockerCompose: null,
rancherCompose: null,
classNames: ['row'],
didReceiveAttrs() {
this.highlightAll();
},
highlightAll() {
Ember.run.next(() => {
this.$('CODE').each(function(idx, elem) {
Prism.highlightElement(elem);
});
});
},
// The highlighting breaks Ember's link to the content, so it's not automatically updated
// when the content change.. manually trigger that.
yamlChanged: function() {
this.$('CODE.docker-compose').html(this.get('dockerCompose'));
this.$('CODE.rancher-compose').html(this.get('rancherCompose'));
this.highlightAll();
}.observes('dockerCompose','rancherCompose'),
});

View File

@ -0,0 +1,8 @@
<div class="col-md-6">
docker-compose.yml {{zero-clipboard text=dockerCompose}}
<pre class="line-numbers"><code class="docker-compose language-yaml">{{dockerCompose}}</code></pre>
</div>
<div class="col-md-6">
rancher-compose.yml {{zero-clipboard text=rancherCompose}}
<pre class="line-numbers"><code class="rancher-compose language-yaml">{{rancherCompose}}</code></pre>
</div>

View File

@ -1,11 +1,12 @@
import NewAlias from 'ui/components/new-aliasservice/component';
import NewOrEdit from 'ui/mixins/new-or-edit';
import Ember from 'ember';
export default NewAlias.extend({
export default Ember.Component.extend(NewOrEdit, {
existing: Ember.computed.alias('originalModel'),
editing: true,
service: null,
primaryResource: Ember.computed.alias('service'),
actions: {
done() {
@ -21,4 +22,12 @@ export default NewAlias.extend({
var original = this.get('originalModel');
this.set('service', original.clone());
},
doneSaving: function() {
this.send('done');
},
didInsertElement() {
this.$('INPUT')[0].focus();
},
});

View File

@ -1,14 +1,11 @@
<section class="header">
{{#link-to "environments" tagName="h1" href=false}}<a>Stack:</a>{{/link-to}}
<h1>{{#link-to "environments"}}Stack:{{/link-to}}</h1>
{{#power-select options=all selected=model onchange=(action "changeStack") searchField="displayName" as |obj|}}
<div class="clip r-pr15"><i class="{{obj.stateIcon}} {{obj.stateColor}}" tooltip="{{obj.displayState}}" data-placement="left"></i> {{obj.displayName}}</div>
{{/power-select}}
<div class="btn-group pull-right">
{{#link-to "environment.index" classNames="btn btn-sm btn-default"}}<i class="icon icon-tasks" data-placement="bottom" tooltip="List"></i>{{/link-to}}
{{#link-to "environment.graph" classNames="btn btn-sm btn-default"}}<i class="icon icon-share" data-placement="bottom" tooltip="Link Graph"></i>{{/link-to}}
{{#link-to "environment.code" classNames="btn btn-sm btn-default"}}<i class="icon icon-file" data-placement="bottom" tooltip="Compose YAML"></i>{{/link-to}}
</div>
{{header-state model=model}}
<div class="left-divider">
{{#if outputs.length}}
@ -43,13 +40,11 @@
{{action-menu model=model classNames="left-divider r-ml5" size="sm"}}
<div class="btn-group left-divider">
{{#link-to "environment.index" classNames="btn btn-sm btn-default"}}<i class="icon icon-tasks" data-placement="bottom" tooltip="List"></i>{{/link-to}}
{{#link-to "environment.graph" classNames="btn btn-sm btn-default"}}<i class="icon icon-share" data-placement="bottom" tooltip="Link Graph"></i>{{/link-to}}
{{#link-to "environment.code" classNames="btn btn-sm btn-default"}}<i class="icon icon-file" data-placement="bottom" tooltip="Compose YAML"></i>{{/link-to}}
</div>
{{upgrade-btn environmentResource=model classNames="left-divider"}}
{{#if (and model.isError model.showTransitioningMessage)}}
<div class="pull-right clip text-danger">
{{model.transitioningMessage}}
</div>
{{/if}}
{{header-state model=model}}
</section>

View File

@ -43,7 +43,7 @@
{{form-key-value
initialMap=machine.engineLabel
changed=(action (mut machine.engineLabel))
nameLabel="Label"
nameLabel="Engine Label"
keyLabel="Label"
}}
</div>

View File

@ -96,7 +96,7 @@
<div class="col-sm-12 col-md-8">
<div class="form-control-static">
<button class="btn-circle" {{action "addDns"}}><i class="icon icon-plus-circle"/></button>
<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">

View File

@ -1,6 +1,6 @@
import Ember from 'ember';
export default Ember.Component.extend({
classNames: ['pull-right','section','r-mt5'],
classNames: ['header-state','pull-right','section','r-mt5'],
classNameBindings: ['model.stateColor'],
});
});

View File

@ -1,6 +1,6 @@
<h4>Host</h4>
<h4>Host Registration URL</h4>
<hr>
<h5>We need to know a little about how your environment is set up before you can register hosts. What base URL should hosts use to connect to the Rancher API?</h5>
<h5>What base URL should hosts use to connect to the Rancher API?</h5>
<div style="margin-top: 15px;">
<label>{{radio-button selection=customRadio value="no"}}&nbsp;This site's address:&nbsp;&nbsp;</label>

View File

@ -21,7 +21,6 @@ export default Ember.Component.extend(NewOrEdit, {
questionsArray: null,
selectedTemplateUrl: null,
selectedTemplateModel: null,
showReadme: true,
readmeContent: null,
actions: {
@ -44,10 +43,6 @@ export default Ember.Component.extend(NewOrEdit, {
changeTemplate: function(tpl) {
this.get('application').transitionToRoute('applications-tab.catalog.launch', tpl.id);
},
toggleReadMe: function() {
this.toggleProperty('showReadme');
}
},
didReceiveAttrs() {

View File

@ -1,61 +1,45 @@
<section class="header">
{{#link-to "applications-tab.catalog" tagName="h1" href=false}}<a>Catalog</a>{{/link-to}}
{{#if editing}}
{{templateResource.name}}
{{else}}
{{#power-select options=allTemplates selected=templateResource onchange=(action "changeTemplate") searchField="name" as |obj|}}
<div class="power-select-img"><img src="{{obj.links.icon}}"><div class="clip">{{obj.name}}</div></div>
{{/power-select}}
{{/if}}
<h1>{{#link-to "applications-tab.catalog"}}Catalog:{{/link-to}}</h1>
{{#if editing}}
{{templateResource.name}}
{{else}}
{{#power-select options=allTemplates selected=templateResource onchange=(action "changeTemplate") searchField="name" as |obj|}}
<div class="power-select-img"><img src="{{obj.links.icon}}"><div class="clip">{{obj.name}}</div></div>
{{/power-select}}
{{/if}}
</section>
<div class="container">
<section>
<div class="well row">
<div class="col-sm-2 col-md-2">
<div class="col-sm-12 col-md-3">
{{#if templateResource.links.icon}}
<img src={{templateResource.links.icon}} alt={{templateResource.name}} class="r-mr20" style="height:75px;max-width: 100%;">
{{/if}}
<div>
<small><strong>Catalog:</strong> <span class="text-capitalize">{{templateResource.catalogId}}</span></small>
</div>
<div>
<small><strong>Category:</strong> {{templateResource.category}}</small>
</div>
<div>
<small><strong>Release By:</strong> {{templateResource.maintainer}}</small>
<small><strong>Maintainer:</strong> {{templateResource.maintainer}}</small>
</div>
<div>
<small><strong>Requires:</strong> {{templateResource.minimumRancherVersion}}</small>
</div>
<div>
<small><strong>License:</strong> {{templateResource.license}}</small>
<small><strong>License:</strong> {{#if templateResource.license}}{{templateResource.license}}{{else}}<span class="text-muted">?</span>{{/if}}</small>
</div>
</div>
<div class="col-sm-10 col-md-10" style="min-height:160px;">
{{#if readmeContent}}
<div class="col-sm-12 col-md-9" style="overflow-y: auto; max-height: 500px;">
{{common-mark markdown=readmeContent}}
</div>
{{else}}
<h2 class="r-mb10">
{{if editing "Upgrade" "Add"}} {{templateResource.name}} Stack {{#if editing}}&quot;{{environmentResource.name}}&quot;{{/if}}
</h2>
<p>{{templateResource.description}}</p>
</div>
{{#if readmeContent}}
<div class="col-sm-10 col-md-10 col-sm-offset-2 col-md-offset-2">
<div class="over-hr r-mt5 r-mb15">
<span style="text-transform: none;">
<nav>
<ul class="pagination pagination-sm r-m0">
<li class="">
<a href="#" {{action 'toggleReadMe'}}>{{if showReadme 'Hide' 'Show'}} Read Me</a>
</li>
</ul>
</nav>
</span>
</div>
{{#liquid-if showReadme}}
{{common-mark markdown=readmeContent}}
{{/liquid-if}}
</div>
{{/if}}
</div>
</section>

View File

@ -103,6 +103,7 @@
<ul class="nav nav-tabs nav-tabs-well shadowed" style="display: inline-block">
{{#if isVm}}
<li role="presentation" class="tab" data-section="disks" {{action "selectTab" "disks"}}><a>Disks</a></li>
<li role="presentation" class="tab" data-section="userdata" {{action "selectTab" "userdata"}}><a>User Data</a></li>
{{else}}
<li role="presentation" class="tab" data-section="command" {{action "selectTab" "command"}}><a>Command</a></li>
<li role="presentation" class="tab" data-section="volumes" {{action "selectTab" "volumes"}}><a>Volumes</a></li>
@ -110,7 +111,6 @@
<li role="presentation" class="tab" data-section="security" {{action "selectTab" "security"}}><a>Security/Host</a></li>
{{/if}}
<li role="presentation" class="tab" data-section="userdata" {{action "selectTab" "userdata"}}><a>User Data</a></li>
<li role="presentation" class="tab" data-section="healthcheck" {{action "selectTab" "healthcheck"}}><a>Health Check</a></li>
<li role="presentation" class="tab" data-section="labels" {{action "selectTab" "labels"}}><a>Labels</a></li>
<li role="presentation" class="tab" data-section="scheduling" {{action "selectTab" "scheduling"}}><a>Scheduling</a></li>
@ -121,6 +121,10 @@
<div class="section container-fluid" data-section="disks">
{{form-disks instance=launchConfig}}
</div>
<div class="section container-fluid" data-section="userdata">
{{form-userdata instance=launchConfig}}
</div>
{{else}}
<div class="section container-fluid" data-section="command">
{{form-command
@ -152,10 +156,6 @@
</div>
{{/if}}
<div class="section container-fluid" data-section="userdata">
{{form-userdata instance=launchConfig}}
</div>
<div class="section container-fluid" data-section="healthcheck">
{{form-healthcheck healthCheck=launchConfig.healthCheck errors=healthCheckErrors}}
</div>

View File

@ -133,11 +133,11 @@
</div>
{{/if}}
{{#if isAdminTab}}
{{#link-to "admin-tab.audit-logs"}}<i class="icon icon-folder-open"></i>Audit Log{{/link-to}}
{{#link-to "admin-tab.processes"}}<i class="icon icon-processes"></i>Processes{{/link-to}}
{{#link-to "admin-tab.accounts"}}<i class="icon icon-users"></i>Accounts{{/link-to}}
{{#link-to "admin-tab.auth"}}<i class="icon icon-key"></i>Access Control{{/link-to}}
{{#link-to "admin-tab.settings"}}<i class="icon icon-network"></i>Settings{{/link-to}}
{{#link-to "admin-tab.processes"}}<i class="icon icon-processes"></i>Processes{{/link-to}}
{{#link-to "admin-tab.audit-logs"}}<i class="icon icon-folder-open"></i>Audit Logs{{/link-to}}
{{/if}}
</nav>
</div>

View File

@ -1,64 +1,47 @@
<div class="clearfix {{if single 'single'}}">
{{#unless single}}
{{#unless single}}
<div class="clearfix">
<div class="stack-state {{model.stateBackground}}"><i class="{{model.stateIcon}}"></i></div>
{{/unless}}
<div class="header-left collapser">
{{#unless single}}
<div class="header-left collapser">
<a {{action "toggleCollapse"}} class="btn btn-link"><i class="icon {{if collapsed 'icon-plus' 'icon-minus'}}" alt="Toggle stack details" title=""></i></a>
{{/unless}}
</div>
</div>
<div class="header-left">
{{#if single}}
<label class="section" style="color:white;">
State: {{model.displayState~}}
{{#if model.showTransitioningMessage}}
<span class="force-wrap">
({{model.transitioningMessage}})
</span>
{{/if}}
</label>
{{else}}
<div class="header-left">
<h4>
<span class="divider clip">{{#link-to "environment" model.id}}{{model.name}}{{/link-to}}</span>
</h4>
{{/if}}
</div>
{{#if (and (not single) outputs.length)}}
<div class="header-left">
<div class="btn-group r-ml10">
<button type="button" class="btn btn-sm btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Outputs <i class="icon icon-chevron-down"></i>
</button>
<ul class="dropdown-menu dropdown-menu-right">
{{#each outputs as |obj|}}
<li><a href="{{obj.value}}" target="_blank">{{obj.key}}</a></li>
{{/each}}
</ul>
</div>
</div>
{{/if}}
<div class="header-right right-divider stack-actions wide">
{{#unless single}}
{{#if outputs.length}}
<div class="header-left">
<div class="btn-group r-ml10">
<button type="button" class="btn btn-sm btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Outputs <i class="icon icon-chevron-down"></i>
</button>
<ul class="dropdown-menu dropdown-menu-right">
{{#each outputs as |obj|}}
<li><a href="{{obj.value}}" target="_blank">{{obj.key}}</a></li>
{{/each}}
</ul>
</div>
</div>
{{/if}}
<div class="header-right right-divider stack-actions wide">
{{action-menu model=model}}
{{/unless}}
</div>
</div>
<div class="header-right right-divider count">
<p>{{instanceCount}}</p>
<label>Container{{unless (eq instanceCount 1) 's'}}</label>
</div>
<div class="header-right right-divider count">
<p>{{instanceCount}}</p>
<label>Container{{unless (eq instanceCount 1) 's'}}</label>
</div>
<div class="header-right right-divider count">
<p>{{model.unremovedServices.length}}</p>
<label>Service{{unless (eq model.unremovedServices.length 1) 's'}}</label>
</div>
<div class="header-right right-divider count">
<p>{{model.unremovedServices.length}}</p>
<label>Service{{unless (eq model.unremovedServices.length 1) 's'}}</label>
</div>
<div class="header-right right-divider stack-template">
{{#unless single}}
<div class="header-right right-divider stack-template">
{{upgrade-btn environmentResource=model}}
<div class="btn-group">
{{#link-to "service.new" (query-params environmentId=model.id) classNames="btn btn-default btn-sm"}}Add Service{{/link-to}}
@ -75,10 +58,9 @@
{{/if}}
</ul>
</div>
{{/unless}}
</div>
</div>
</div>
{{/unless}}
{{#liquid-if (not collapsed)}}
<div class="stack-body {{if single 'single-body'}}">

View File

@ -1,15 +1,13 @@
<section class="header">
{{#link-to "containers" tagName="h1" href=false}}<a>Container:</a>{{/link-to}}
<h1>{{#link-to "containers"}}Container:{{/link-to}}</h1>
{{#power-select options=model.primaryHost.instances selected=model onchange=(action "changeContainer") searchField="displayName" as |obj|}}
<div class="clip r-mr15">
<i class="{{obj.stateIcon}} {{obj.stateColor}}" tooltip="{{obj.displayState}}" data-placement="left"></i> {{obj.displayName}}
</div>
{{/power-select}}
<strong>on {{#link-to "host" model.primaryHost.id}}{{model.primaryHost.displayName}}{{/link-to}}</strong>
<strong>on {{#link-to "host" model.primaryHost.id href=false}}<a>{{model.primaryHost.displayName}}</a>{{/link-to}}</strong>
{{action-menu model=model size="sm"}}
{{header-state model=model}}
</section>

View File

@ -6,13 +6,14 @@ export default Ember.Route.extend({
var stack = par.get('stack');
return stack.doAction('exportconfig').then((config) => {
// Windows needs CRLFs
config.dockerComposeConfig = config.dockerComposeConfig.split(/\r?\n/).join('\r\n');
config.rancherComposeConfig = config.rancherComposeConfig.split(/\r?\n/).join('\r\n');
var dockerCompose = config.dockerComposeConfig.split(/\r?\n/).join('\r\n');
var rancherCompose = config.rancherComposeConfig.split(/\r?\n/).join('\r\n');
return Ember.Object.create({
stack: stack,
all: par.get('all'),
composeConfig: config
dockerCompose: dockerCompose,
rancherCompose: rancherCompose,
});
});
},

View File

@ -1,16 +1,8 @@
{{environment-header model=model.stack all=model.all}}
<section>
<div class="row">
<div class="col-md-6">
docker-compose.yml {{zero-clipboard text=model.composeConfig.dockerComposeConfig}}
<pre class="line-numbers"><code class="language-yaml">
{{model.composeConfig.dockerComposeConfig}}</code></pre>
</div>
<div class="col-md-6">
rancher-compose.yml {{zero-clipboard text=model.composeConfig.rancherComposeConfig}}
<pre class="line-numbers"><code class="language-yaml">
{{model.composeConfig.rancherComposeConfig}}</code></pre>
</div>
</div>
{{compose-yaml
dockerCompose=model.dockerCompose
rancherCompose=model.rancherCompose
}}
</section>

View File

@ -1,18 +0,0 @@
import Ember from 'ember';
export default Ember.View.extend({
didInsertElement: function() {
this._super();
this.highlightAll();
},
highlightAll: function() {
this.$('CODE').each(function(idx, elem) {
Prism.highlightElement(elem);
});
},
yamlChanged: function() {
this.highlightAll();
}.observes('context.model.composeConfig.{dockerComposeConfig,rancherComposeConfig}'),
});

View File

@ -1,10 +1,10 @@
<section class="header">
{{#link-to "hosts" tagName="h1" href=false}}<a>Host:</a>{{/link-to}}
<h1>{{#link-to "hosts"}}Host:{{/link-to}}</h1>
{{#power-select options=model.all selected=host onchange=(action "changeHost") searchField="displayName" as |obj|}}
<div class="clip"><i class="{{obj.stateIcon}} {{obj.stateColor}}" tooltip="{{obj.displayState}}" data-placement="left"></i> {{obj.displayName}}</div>
{{/power-select}}
{{#action-menu model=host size="sm" classNames="left-divider"}}
{{#link-to "containers.new" (query-params hostId=host.id) classNames="btn btn-sm btn-primary"}}Add Container{{/link-to}}
{{/action-menu}}

View File

@ -1,6 +1,6 @@
<section class="header">
<h1 class="right-divider">
{{#link-to "infrastructure-tab" tagName="li" href=false}}<a>Hosts</a>{{/link-to}}
{{#link-to "infrastructure-tab"}}Hosts:{{/link-to}}
Add Host
</h1>
</section>

View File

@ -19,14 +19,15 @@ function serialize(obj) {
}
}
var auditLog = Resource.extend({});
var AuditLog = Resource.extend({});
auditLog.reopenClass({
AuditLog.reopenClass({
headers: {
[C.HEADER.PROJECT]: undefined, // Requests for projects use the user's scope, not the project
},
mangleIn: function(data) {
// request and responseObject should be plain JSON objects, not typeified.
if ( data.requestObject )
{
data.requestObject = serialize(data.requestObject);
@ -42,4 +43,4 @@ auditLog.reopenClass({
});
export default auditLog;
export default AuditLog;

View File

@ -106,7 +106,7 @@ var Container = Resource.extend({
var resource = this.get('state');
var health = this.get('healthState');
if ( ['running','active','updating-active'].indexOf(resource) >= 0 )
if ( C.ACTIVEISH_STATES.indexOf(resource) >= 0 )
{
if ( health === null || health === 'healthy' )
{

View File

@ -126,7 +126,7 @@ var Environment = Resource.extend({
unremoved++;
if ( ['running','active','updating-active'].indexOf(resource) >= 0 && health === 'healthy' )
if ( C.ACTIVEISH_STATES.indexOf(resource) >= 0 && health === 'healthy' )
{
healthy++;
}

View File

@ -306,8 +306,9 @@ var Service = Resource.extend({
instances.forEach((instance) => {
var resource = instance.get('state');
var health = instance.get('healthState');
var startOnce = instance.get('labels')[C.LABEL.START_ONCE] === true;
if ( ['running','active','updating-active'].indexOf(resource) >= 0 && (health === 'healthy' || health === null) )
if ( C.ACTIVEISH_STATES.indexOf(resource) >= 0 && (health === 'healthy' || health === null) )
{
healthy++;
}

View File

@ -1,12 +1,10 @@
<section class="header">
<h1>
Service:
</h1>
<h1>Service:</h1>
{{#power-select options=model.stack.services selected=service onchange=(action "changeService") searchField="displayName" as |obj|}}
<div class="clip"><i class="{{obj.stateIcon}} {{obj.stateColor}}" tooltip="{{obj.displayState}}" data-placement="left"></i> {{obj.displayName}}</div>
{{/power-select}}
<strong>in {{#link-to "environment" model.stack.id}}{{model.stack.displayName}}{{/link-to}}</strong>
{{action-menu model=service classNames="r-ml5" size="sm"}}
{{header-state model=service}}
</section>

View File

@ -16,7 +16,7 @@ export default Ember.Service.extend(Ember.Evented, {
init() {
this._super();
this.set('all', this.get('store').allUnremoved('activesetting'));
this.set('all', this.get('store').all('activesetting'));
},
unknownProperty(key) {

View File

@ -21,7 +21,7 @@ $lines-to-show: 4;
h5 {
border-bottom: solid thin $lightGray;
text-align: left;
padding: 15px;
padding: 15px 0;
margin: 0 15px;
}

View File

@ -763,6 +763,10 @@ SECTION.header {
}
}
.header-state {
margin-left: 10px;
}
.sad-ie {
background-image: url('images/sad-ie.png');
width: 300px;

View File

@ -1,15 +1,16 @@
import Ember from 'ember';
export default Ember.ArrayProxy.extend(Ember.SortableMixin, {
export default Ember.ArrayProxy.extend({
sourceContent: null,
sortProperties: null,
init: function() {
if ( !this.get('sortProperties') )
{
this.set('sortProperties', ['name','id']);
this.set('sortProperties', ['displayName','name','id']);
}
this.sourceContentChanged();
this._super();
this.set('content', []);
},
sourceContentChanged: function() {
@ -17,5 +18,8 @@ export default Ember.ArrayProxy.extend(Ember.SortableMixin, {
return (Ember.get(item,'state')||'').toLowerCase() === 'active';
});
this.set('content', x);
}.observes('sourceContent.@each.state').on('init'),
}.observes('sourceContent.@each.state'),
// The array proxy reads this property
arrangedContent: Ember.computed.sort('content','sortProperties'),
});

View File

@ -1,40 +1,17 @@
var C = {
PREFS: {
ACCESS_WARNING: 'accessWarning',
PROJECT_DEFAULT: 'defaultProjectId',
I_HATE_SPINNERS: 'iHateSpinners',
EXPANDED_STACKS: 'expandedStacks',
SORT_STACKS_BY: 'sortStacksBy',
},
COOKIE: {
TOKEN: 'token',
},
SESSION: {
BACK_TO: 'backTo',
USER_ID: 'user',
ACCOUNT_ID: 'accountId',
USER_TYPE: 'userType',
PROJECT: 'projectId',
IDENTITY: 'userIdentity',
IDENTITY_TYPE: 'userType',
GITHUB_CACHE: 'githubCache',
GITHUB_ORGS: 'orgs',
GITHUB_TEAMS: 'teams',
},
HEADER: {
PROJECT: 'x-api-project-id',
NO_CHALLENGE: 'x-api-no-challenge',
NO_CHALLENGE_VALUE: 'true',
ACCOUNT_ID: 'x-api-account-id',
},
USER: {
TYPE_NORMAL: 'user',
TYPE_ADMIN: 'admin',
BASIC_BEARER: 'x-api-bearer',
EXTERNALID: {
KIND_SEPARATOR: '://',
GROUP_SEPARATOR: ':',
KIND_ALL: 'all',
KIND_USER: 'user',
KIND_CATALOG: 'catalog',
KIND_SYSTEM: 'system',
KIND_KUBERNETES: 'kubernetes',
CATALOG_DEFAULT_GROUP: 'library',
},
GITHUB: {
@ -44,35 +21,11 @@ var C = {
SCOPE: 'read:org',
},
PROJECT: {
TYPE_RANCHER: 'rancher_id',
TYPE_GITHUB_USER: 'github_user',
TYPE_GITHUB_TEAM: 'github_team',
TYPE_GITHUB_ORG: 'github_org',
TYPE_LDAP_USER: 'ldap_user',
TYPE_LDAP_GROUP: 'ldap_group',
TYPE_OPENLDAP_USER: 'openldap_user',
TYPE_OPENLDAP_GROUP: 'openldap_group',
PERSON: 'person',
TEAM: 'team',
ORG: 'org',
ROLE_MEMBER: 'member',
ROLE_OWNER: 'owner',
},
SETTING: {
// Dots in key names do not mix well with Ember, so use $ in their place.
DOT_CHAR: '$',
VERSION_RANCHER: 'rancher$server$image',
VERSION_COMPOSE: 'rancher$compose$version',
VERSION_CATTLE: 'cattle$version',
VERSION_MACHINE: 'docker$machine$version',
VERSION_GMS: 'go$machine$service$version',
API_HOST: 'api$host',
CATALOG_URL: 'catalog$url',
VM_ENABLED: 'vm$enabled',
HEADER: {
PROJECT: 'x-api-project-id',
NO_CHALLENGE: 'x-api-no-challenge',
NO_CHALLENGE_VALUE: 'true',
ACCOUNT_ID: 'x-api-account-id',
},
KEY: {
@ -113,15 +66,62 @@ var C = {
KVM: 'io.rancher.host.kvm',
},
EXTERNALID: {
KIND_SEPARATOR: '://',
GROUP_SEPARATOR: ':',
KIND_ALL: 'all',
KIND_USER: 'user',
KIND_CATALOG: 'catalog',
KIND_SYSTEM: 'system',
KIND_KUBERNETES: 'kubernetes',
CATALOG_DEFAULT_GROUP: 'library',
PREFS: {
ACCESS_WARNING: 'accessWarning',
PROJECT_DEFAULT: 'defaultProjectId',
I_HATE_SPINNERS: 'iHateSpinners',
EXPANDED_STACKS: 'expandedStacks',
SORT_STACKS_BY: 'sortStacksBy',
},
PROJECT: {
TYPE_RANCHER: 'rancher_id',
TYPE_GITHUB_USER: 'github_user',
TYPE_GITHUB_TEAM: 'github_team',
TYPE_GITHUB_ORG: 'github_org',
TYPE_LDAP_USER: 'ldap_user',
TYPE_LDAP_GROUP: 'ldap_group',
TYPE_OPENLDAP_USER: 'openldap_user',
TYPE_OPENLDAP_GROUP: 'openldap_group',
PERSON: 'person',
TEAM: 'team',
ORG: 'org',
ROLE_MEMBER: 'member',
ROLE_OWNER: 'owner',
},
SESSION: {
BACK_TO: 'backTo',
USER_ID: 'user',
ACCOUNT_ID: 'accountId',
USER_TYPE: 'userType',
PROJECT: 'projectId',
IDENTITY: 'userIdentity',
IDENTITY_TYPE: 'userType',
GITHUB_CACHE: 'githubCache',
GITHUB_ORGS: 'orgs',
GITHUB_TEAMS: 'teams',
},
SETTING: {
// Dots in key names do not mix well with Ember, so use $ in their place.
DOT_CHAR: '$',
VERSION_RANCHER: 'rancher$server$image',
VERSION_COMPOSE: 'rancher$compose$version',
VERSION_CATTLE: 'cattle$version',
VERSION_MACHINE: 'docker$machine$version',
VERSION_GMS: 'go$machine$service$version',
API_HOST: 'api$host',
CATALOG_URL: 'catalog$url',
VM_ENABLED: 'vm$enabled',
},
USER: {
TYPE_NORMAL: 'user',
TYPE_ADMIN: 'admin',
BASIC_BEARER: 'x-api-bearer',
},
};
@ -148,4 +148,14 @@ C.SYSTEM_LABELS_WITH_CONTROL = [
C.LABEL.PULL_IMAGE,
];
C.ACTIVEISH_STATES = [
'running',
'active',
'updating-active',
'updating-running',
'healthy',
'degraded',
'unhealthy'
];
export default C;

View File

@ -1,5 +1,6 @@
import Ember from "ember";
import Socket from "ui/utils/socket";
import C from 'ui/utils/constants';
/*
Usage:
@ -27,7 +28,7 @@ export default Ember.Object.extend(Ember.Evented, {
},
available: function() {
return ['running','updating-running','active','updating-active','unhealthy'].indexOf(this.get('resource.state')) >= 0;
return C.ACTIVEISH_STATES.indexOf(this.get('resource.state')) >= 0;
}.property('resource.state'),
active: Ember.computed.and('available', 'connected'),

View File

@ -1,15 +1,16 @@
import Ember from 'ember';
export default Ember.ArrayProxy.extend(Ember.SortableMixin, {
export default Ember.ArrayProxy.extend({
sourceContent: null,
sortProperties: null,
init: function() {
if ( !this.get('sortProperties') )
{
this.set('sortProperties', ['name','id']);
this.set('sortProperties', ['displayName','name','id']);
}
this.sourceContentChanged();
this._super();
this.set('content', []);
},
sourceContentChanged: function() {
@ -17,5 +18,8 @@ export default Ember.ArrayProxy.extend(Ember.SortableMixin, {
return (Ember.get(item,'state')||'').toLowerCase() !== 'purged';
});
this.set('content', x);
}.observes('sourceContent.@each.state').on('init'),
}.observes('sourceContent.@each.state'),
// The array proxy gets it's data from here
arrangedContent: Ember.computed.sort('content','sortProperties'),
});

View File

@ -1,21 +1,27 @@
import Ember from 'ember';
export default Ember.ArrayProxy.extend(Ember.SortableMixin, {
var undesireable = ['removed','purging','purged'];
export default Ember.ArrayProxy.extend({
sourceContent: null,
sortProperties: null,
init: function() {
if ( !this.get('sortProperties') )
{
this.set('sortProperties', ['name','id']);
this.set('sortProperties', ['displayName','name','id']);
}
this.sourceContentChanged();
this._super();
this.set('content', []);
},
sourceContentChanged: function() {
var x = (this.get('sourceContent')||[]).filter(function(item) {
return ['removed','purging','purged'].indexOf((Ember.get(item,'state')||'').toLowerCase()) === -1;
return undesireable.indexOf((Ember.get(item,'state')||'').toLowerCase()) === -1;
});
this.set('content', x);
}.observes('sourceContent.@each.state').on('init'),
}.observes('sourceContent.@each.state'),
// The array proxy reads this property
arrangedContent: Ember.computed.sort('content','sortProperties'),
});

View File

@ -6,7 +6,7 @@ export default Ember.Route.extend({
return store.find('virtualmachine', params.virtualmachine_id).then(function(vm) {
var host = vm.get('primaryHost');
if ( host.get('instances') )
if ( !host || host.get('instances') )
{
return vm;
}

View File

@ -1,19 +1,16 @@
<section class="header">
<h1 class="right-divider">
{{#if model.vm.primaryHost}}
{{#link-to "hosts" tagName="li" href=false}}<a>Hosts</a>{{/link-to}}
{{#link-to "host" model.vm.primaryHost.id tagName="li" href=false}}<a>{{model.vm.primaryHost.displayName}}</a>{{/link-to}}
{{else}}
{{#link-to "virtualmachines" tagName="li" href=false}}<a>Virtual Machines</a>{{/link-to}}
{{/if}}
{{#power-select options=model.vm.primaryHost.instances selected=model.vm onchange=(action "changeVirtualMachine") searchField="displayName" as |obj|}}
<div class="clip r-mr15"><i class="{{obj.stateIcon}} {{obj.stateColor}}" tooltip="{{obj.displayState}}" data-placement="left"></i> {{obj.displayName}}</div>
{{/power-select}}
</h1>
<h1>{{#link-to "virtualmachines"}}Virtual Machine:{{/link-to}}</h1>
{{#power-select options=model.vm.primaryHost.instances selected=model.vm onchange=(action "changeVirtualMachine") searchField="displayName" as |obj|}}
<div class="clip r-mr15"><i class="{{obj.stateIcon}} {{obj.stateColor}}" tooltip="{{obj.displayState}}" data-placement="left"></i> {{obj.displayName}}</div>
{{/power-select}}
{{#if model.vm.primaryHost}}
<strong>on {{#link-to "host" model.vm.primaryHost.id}}{{model.vm.primaryHost.displayName}}{{/link-to}}</strong>
{{/if}}
{{action-menu model=model.vm size="sm"}}
{{header-state model=model.vm}}
</section>
<section>

View File

@ -908,9 +908,9 @@ $text-muted: #999;
//** Abbreviations and acronyms border color
$abbr-border-color: $gray-light;
//** Headings small color
$headings-small-color: $gray-light;
$headings-small-color: $gray;
//** Blockquote small color
$blockquote-small-color: $gray-light;
$blockquote-small-color: $gray;
//** Blockquote font size
$blockquote-font-size: ($font-size-base * 1.25);
//** Blockquote border color