Merge pull request #892 from vincent99/master

Bugs
This commit is contained in:
Vincent Fiduccia 2016-11-14 16:59:43 -07:00 committed by GitHub
commit 3a684368c5
30 changed files with 203 additions and 151 deletions

View File

@ -50,10 +50,11 @@ ${image}`;
promptPanic() {
this.set('confirmPanic', true);
Ember.run.later(() => {
if ( !this.isDestroyed )
{
this.set('confirmPanic', false);
if ( this.isDestroyed || this.isDestroying ) {
return;
}
this.set('confirmPanic', false);
}, 5000);
},

View File

@ -133,9 +133,11 @@ export default Ember.Component.extend(ThrottledResize, {
};
socket.onclose = () => {
if ( !this.isDestroyed ) {
this.set('status','disconnected');
if ( this.isDestroyed || this.isDestroying ) {
return;
}
this.set('status','disconnected');
};
},

View File

@ -74,10 +74,11 @@ export default Ember.Component.extend({
add() {
this.get('ary').pushObject(Ember.Object.create({key: '', value: ''}));
Ember.run.next(() => {
if ( !this.isDestroyed )
{
this.$('INPUT.key').last()[0].focus();
if ( this.isDestroyed || this.isDestroying ) {
return;
}
this.$('INPUT.key').last()[0].focus();
});
},
@ -131,8 +132,7 @@ export default Ember.Component.extend({
}.observes('ary.@each.{key,value}'),
fireChanged() {
if ( this.isDestroyed )
{
if ( this.isDestroyed || this.isDestroying ) {
return;
}

View File

@ -67,9 +67,11 @@ export default Ember.Component.extend({
didInsertElement() {
Ember.run.next(() => {
if ( !this.isDestroyed ) {
this.$('INPUT')[0].focus();
if ( this.isDestroyed || this.isDestroying ) {
return;
}
this.$('INPUT')[0].focus();
});
},
});

View File

@ -1,6 +1,6 @@
<div class="{{if editing 'form-group' ''}}">
{{#if canRequestHost}}
{{#if editing}}
{{#if editing}}
{{#if canRequestHost}}
<div class="radio r-mb0">
<label class="form-control-static">{{radio-button selection=isRequestedHost value=true}}
{{#if isService}}
@ -42,37 +42,41 @@
</label>
</div>
{{else}}
{{#if requestedHostId}}
<div class="component-static">
<div class="row">
<label class="form-control-static">
{{#if isService}}
{{#if (eq isVm 'virtual machines')}}
{{format-html-message 'formScheduling.canRequestHost.vm'}}
{{else}}
{{format-html-message 'formScheduling.canRequestHost.containers'}}
{{/if~}}
{{else}}
{{t 'formScheduling.runSpecific'}}
{{/if}}
</label>
<span class="form-static-control">{{selectedChoice.name}}</span>
</div>
</div>
{{#if isService}}
{{#if isGlobal}}
{{t 'formScheduling.autoRun'}}
{{else if isVm}}
{{t 'formScheduling.autoPick.vm'}}
{{else}}
{{t 'formScheduling.autoPick.container'}}
{{/if~}}
{{else}}
{{t 'formScheduling.autoPick.host'}}
{{/if}}
{{/if}}
{{else if isGlobal}}
{{t 'formScheduling.autoRun'}}
{{else if requestedHostId}}
<div class="component-static">
<div class="row">
<label class="form-control-static">
{{#if isService}}
{{#if (eq isVm 'virtual machines')}}
{{format-html-message 'formScheduling.canRequestHost.vm'}}
{{else}}
{{format-html-message 'formScheduling.canRequestHost.containers'}}
{{/if~}}
{{else}}
{{t 'formScheduling.runSpecific'}}
{{/if}}
</label>
<span class="form-static-control">{{selectedChoice.name}}</span>
</div>
</div>
{{else if (eq isVm 'virtual machines')}}
{{t 'formScheduling.autoPick.vm'}}
{{else}}
{{#if isService}}
{{#if isGlobal}}
{{t 'formScheduling.autoRun'}}
{{else if isVm}}
{{t 'formScheduling.autoPick.vm'}}
{{else}}
{{t 'formScheduling.autoPick.container'}}
{{/if~}}
{{else}}
{{t 'formScheduling.autoPick.host'}}
{{/if}}
{{t 'formScheduling.autoPick.container'}}
{{/if}}
{{#unless isRequestedHost}}
@ -110,7 +114,7 @@
</tbody>
</table>
{{else}}
<span class="text-muted">{{t 'formScheduling.noRules'}}</span>
<div class="text-muted">{{t 'formScheduling.noRules'}}</div>
{{/if}}
{{/unless}}
</div>

View File

@ -9,10 +9,11 @@ export default Ember.Component.extend(ManageLabels, {
addUserLabel() {
this._super();
Ember.run.next(() => {
if ( !this.isDestroyed )
{
this.$('INPUT.key').last()[0].focus();
if ( this.isDestroyed || this.isDestroying ) {
return;
}
this.$('INPUT.key').last()[0].focus();
});
}
},

View File

@ -15,10 +15,11 @@ export default Ember.Component.extend({
add() {
this.get('ary').pushObject(Ember.Object.create({value: ''}));
Ember.run.next(() => {
if ( !this.isDestroyed )
{
this.$('INPUT.value').last()[0].focus();
if ( this.isDestroyed || this.isDestroying ) {
return;
}
this.$('INPUT.value').last()[0].focus();
});
},

View File

@ -31,15 +31,19 @@ export default Ember.Component.extend({
{
this.set('loading', true);
this.get('userStore').find('identity', id).then((identity) => {
if ( !this.isDestroyed ) {
this.set('identity', identity);
if ( this.isDestroyed || this.isDestroying ) {
return;
}
this.set('identity', identity);
}).catch((/*err*/) => {
// Do something..
}).finally(() => {
if ( !this.isDestroyed ) {
this.set('loading', false);
if ( this.isDestroyed || this.isDestroying ) {
return;
}
this.set('loading', false);
});
}
}

View File

@ -234,8 +234,7 @@ setupMarkers: function() {
},
onDataPoint(point) {
if ( this.isDestroyed )
{
if ( this.isDestroyed || this.isDestroying ) {
return;
}

View File

@ -115,7 +115,7 @@ export default Ember.Component.extend(HoverDropdown, {
'namespaceId',
'projects.orchestrationState',
'project.virtualMachine',
'stacks.@each.grouping',
'stacks.@each.group',
`settings.${C.SETTING.CATALOG_URL}`,
`prefs.${C.PREFS.ACCESS_WARNING}`,
`k8s.supportsStacks`,

View File

@ -45,10 +45,11 @@ export default Ember.Component.extend({
if ( this.get('saved') )
{
Ember.run.later(this, () => {
if ( !this.isDestroyed )
{
this.set('saved', false);
if ( this.isDestroyed || this.isDestroying ) {
return;
}
this.set('saved', false);
}, 5000);
}
}.observes('saved'),

View File

@ -14,7 +14,7 @@ export default Ember.Component.extend({
this._super(...arguments);
this.get('allServices').choices().then((choices) => {
if ( this.isDestroyed ) {
if ( this.isDestroyed || this.isDestroying ) {
return;
}

View File

@ -17,10 +17,11 @@ export default Ember.Component.extend({
add() {
this.get('ary').pushObject(Ember.Object.create({name: '', branch: 'master', url: ''}));
Ember.run.next(() => {
if ( !this.isDestroyed )
{
this.$('INPUT.name').last()[0].focus();
if ( this.isDestroyed || this.isDestroying ) {
return;
}
this.$('INPUT.name').last()[0].focus();
});
},

View File

@ -75,8 +75,7 @@ export default Ember.Component.extend(ThrottledResize, {
this.updateGraph();
$(outer[0]).on('click', (event) => {
if ( !this.isDestroyed )
{
if ( this.isDestroyed || this.isDestroying ) {
return;
}

View File

@ -32,7 +32,7 @@ export default Ember.TextArea.extend(IntlPlaceholder, {
}.observes('value'),
isSmall: function() {
if ( this.isDestroyed ) {
if ( this.isDestroyed || this.isDestroying ) {
return;
}
@ -40,7 +40,7 @@ export default Ember.TextArea.extend(IntlPlaceholder, {
}.property(),
autoSize() {
if ( this.isDestroyed ) {
if ( this.isDestroyed || this.isDestroying ) {
return;
}

View File

@ -37,8 +37,7 @@ export default Ember.Component.extend({
},
show(node) {
if ( this.isDestroyed )
{
if ( this.isDestroyed || this.isDestroying ) {
return;
}

View File

@ -50,8 +50,7 @@ export default Ember.Component.extend({
var self = this;
function updateState(rfb, state, oldstate, msg) {
if ( this.isDestroyed )
{
if ( this.isDestroyed || this.isDestroying ) {
return;
}

View File

@ -1,6 +1,7 @@
{{form-scheduling
initialHostId=model.container.requestedHostId
initialLabels=model.container.labels
isGlobal=model.container.isGlobalScale
allHosts=model.hosts
editing=false
}}

View File

@ -1,6 +1,6 @@
<section class="header r-pt20 clearfix">
<h1>{{#link-to "containers"}}{{t 'containersPage.containerPage.header'}}{{/link-to}}</h1>
{{#power-select options=model.primaryHost.instances selected=model onchange=(action "changeContainer") searchField="displayName" as |obj|}}
{{#power-select options=model.primaryHost.arrangedInstances selected=model onchange=(action "changeContainer") searchField="displayName" as |obj|}}
<span class="clip r-mr15">
{{select-dot model=obj}}
</span>

View File

@ -2,7 +2,12 @@ import Ember from 'ember';
import Sortable from 'ui/mixins/sortable';
export default Ember.Controller.extend(Sortable, {
show: 'standard',
showSystem: null,
sortBy: 'name',
queryParams: ['show','sortBy'],
sorts: {
state: ['stateSort','name','id'],
name: ['name','id'],
@ -11,4 +16,26 @@ export default Ember.Controller.extend(Sortable, {
command: ['command','name','id'],
host: ['primaryHost.displayName','name','id'],
},
// showChanged should be an observer rather then init to correctly set the showSystem checkbox
// if showSystem is set on init show does not contain the correct qp as the router has not set it
// so the checkbox never gets set
showChanged: function() {
this.set('showSystem', this.get('show') === 'all');
}.observes('show'),
showSystemChanged: function() {
this.set('show', (this.get('showSystem') ? 'all' : 'standard'));
}.observes('showSystem'),
sortableContent: Ember.computed.alias('filtered'),
filtered: function() {
let all = this.get('model');
if ( this.get('showSystem') ) {
return all;
} else {
return all.filterBy('isSystem', false);
}
}.property('model.@each.system','showSystem'),
});

View File

@ -2,6 +2,10 @@
<h1>{{t 'containersPage.index.header'}}</h1>
{{#link-to "containers.new" classNames="btn btn-sm btn-primary"}}{{t 'containersPage.index.linkTo'}}{{/link-to}}
<div class="btn-group pull-right r-mr10 r-mt5">
<label style="font-weight: normal;">{{input type="checkbox" checked=showSystem}} {{t 'hostsPage.index.showSystem'}}</label>
</div>
</section>
<section class="well instances">

View File

@ -16,7 +16,7 @@ export function initialize(/*application */) {
}.on('didInsertElement'),
activeChanged() {
if ( this.isDestroyed ) {
if ( this.isDestroyed || this.isDestroying ) {
return;
}

View File

@ -33,13 +33,13 @@ function getUpgradeInfo(task, cb) {
}
Ember.RSVP.hash(deps).then((hash) => {
let upgradeInfo = hash.upgradeInfo;
let fullInfo = hash.fullInfo;
if ( obj.isDestroyed )
{
if ( this.isDestroyed || this.isDestroying ) {
return;
}
let upgradeInfo = hash.upgradeInfo;
let fullInfo = hash.fullInfo;
if ( !upgradeInfo ) {
obj.set('upgradeStatus', CURRENT);
return;

View File

@ -242,6 +242,10 @@ var Container = Instance.extend({
});
}.property('mounts.@each.state'),
// @TODO PERF
//
isGlobalScale: function() {
return (this.get('labels')||{})[C.LABEL.SCHED_GLOBAL] + '' === 'true';
}.property('labels'),
});
Container.reopenClass({

View File

@ -11,6 +11,9 @@ var Host = Resource.extend({
modalService: Ember.inject.service('modal'),
instances: denormalizeInstanceArray('instanceIds'),
arrangedInstances: function() {
return this.get('instances').sortBy('isSystem','displayName');
}.property('instances.@each.{isSystem,displayName}'),
actions: {
activate: function() {

View File

@ -1,8 +1,7 @@
import Ember from 'ember';
import Sortable from 'ui/mixins/sortable';
import C from 'ui/utils/constants';
import { tagsToArray, tagChoices } from 'ui/models/stack';
import { uniqKeys } from 'ui/utils/util';
import { tagsToArray } from 'ui/models/stack';
export default Ember.Controller.extend(Sortable, {
stacksController: Ember.inject.controller('stacks'),
@ -16,16 +15,6 @@ export default Ember.Controller.extend(Sortable, {
showAddtlInfo: false,
selectedService: null,
tag: null,
tagChoices: function() {
let choices = tagChoices(this.get('model.stacks'));
tagsToArray(this.get('tags')).forEach((tag) => {
choices.addObject(tag);
});
return uniqKeys(choices);
}.property('model.stacks.@each.group'), // tags is derived from group..
actions: {
showAddtlInfo(service) {
this.set('selectedService', service);
@ -41,10 +30,6 @@ export default Ember.Controller.extend(Sortable, {
this.get('prefs').set(C.PREFS.SORT_STACKS_BY, name);
this.send('setSort', name);
},
switchTag(str) {
this.set('tags', str);
},
},
filteredStacks: function() {
@ -81,7 +66,11 @@ export default Ember.Controller.extend(Sortable, {
pageHeader: function() {
let which = this.get('which');
if ( which === C.EXTERNAL_ID.KIND_ALL ) {
let tags = this.get('tags');
if ( tags ) {
return 'stacksPage.header.tags';
} else if ( which === C.EXTERNAL_ID.KIND_ALL ) {
return 'stacksPage.header.all';
} else if ( C.EXTERNAL_ID.SHOW_AS_SYSTEM.indexOf(which) >= 0 ) {
return 'stacksPage.header.infra';

View File

@ -1,6 +1,6 @@
<section class="header">
<h1>
{{t pageHeader name=which}}
{{t pageHeader name=which tags=tags}}
</h1>
{{#if (eq which "infra")}}
@ -19,23 +19,6 @@
<button {{action 'sortResults' 'name'}} type="button" class="btn btn-sm btn-default {{if (eq sortBy "name") 'active'}}">{{t 'stacksPage.sort.name'}}</button>
</div>
</div>
{{#if tagChoices.length}}
<div class="btn-group pull-right r-mr10">
<button type="button" class="btn btn-default btn-sm dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">{{t (if tags 'stacksPage.tags.one' 'stacksPage.tags.all' ) name=tags}} <i class="icon icon-chevron-down"></i></button>
<ul class="dropdown-menu dropdown-menu-right">
<li class="{{if (eq tags '') 'active'}}"><a href="#" {{action 'switchTag' ''}}>{{t 'stacksPage.tags.all'}}</a></li>
<li class="divider"></li>
{{#each tagChoices as |opt|}}
<li class="{{if (eq tags opt) 'active'}}">
<a href="#" {{action 'switchTag' opt}}>
{{opt}}
</a>
</li>
{{/each}}
</ul>
</div>
{{/if}}
</section>
<section class="stacks-wrap r-pl0 r-pr0">

View File

@ -22,9 +22,11 @@ export function debouncedObserver(...args) {
keys = args.slice(0, funcIndex);
var fn = function() {
if ( !this.isDestroyed ) {
opt[0].apply(this);
if ( this.isDestroyed || this.isDestroying ) {
return;
}
opt[0].apply(this);
};
return Ember.observer.apply(Ember, keys.concat(function() {

View File

@ -1,6 +1,8 @@
import Ember from 'ember';
import C from 'ui/utils/constants';
import { getCatalogNames } from 'ui/utils/parse-catalog-setting';
import { tagChoices } from 'ui/models/stack';
import { uniqKeys } from 'ui/utils/util';
// Useful context/condition shortcuts
export const getProjectId = function() { return this.get('projectId'); };
@ -50,7 +52,6 @@ const navTree = [
route: 'k8s-tab',
ctx: [getProjectId],
condition: function() { return this.get('hasKubernetes'); },
moreCurrentWhen: ['authenticated.project.waiting'],
submenu: [
{
id: 'k8s-stacks',
@ -139,7 +140,7 @@ const navTree = [
condition: function() { return this.get('hasProject') && this.get('hasSwarm'); },
route: 'swarm-tab',
ctx: [getProjectId],
moreCurrentWhen: ['authenticated.project.waiting','stacks'],
moreCurrentWhen: ['stacks'],
submenu: [
{
id: 'swarm-projects',
@ -189,7 +190,6 @@ const navTree = [
condition: function() { return this.get('hasProject') && this.get('hasMesos'); },
route: 'mesos-tab',
ctx: [getProjectId],
moreCurrentWhen: ['authenticated.project.waiting'],
submenu: [
{
id: 'mesos-web',
@ -223,40 +223,8 @@ const navTree = [
route: 'stacks',
queryParams: {which: C.EXTERNAL_ID.KIND_USER},
ctx: [getProjectId],
moreCurrentWhen: ['authenticated.project.waiting'],
condition: function() { return this.get('hasProject') && !this.get('hasKubernetes') && !this.get('hasSwarm') && !this.get('hasMesos'); },
submenu: [
{
id: 'cattle-all',
localizedLabel: 'nav.cattle.all',
icon: 'icon icon-globe',
route: 'stacks',
ctx: [getProjectId],
queryParams: {which: C.EXTERNAL_ID.KIND_ALL},
condition: isOwner,
},
{ divider: true ,
condition: isOwner,
},
{
id: 'cattle-user',
localizedLabel: 'nav.cattle.user',
icon: 'icon icon-layers',
route: 'stacks',
ctx: [getProjectId],
queryParams: {which: C.EXTERNAL_ID.KIND_USER},
condition: isOwner,
},
{
id: 'cattle-infra',
localizedLabel: 'nav.cattle.system',
icon: 'icon icon-gear',
route: 'stacks',
ctx: [getProjectId],
condition: isOwner,
queryParams: {which: C.EXTERNAL_ID.KIND_INFRA},
}
]
submenu: getStacksSubtree,
},
// Catalog
@ -432,6 +400,63 @@ export function get() {
return Ember.copy(navTree,true);
}
function getStacksSubtree() {
let out = [
{
id: 'cattle-all',
localizedLabel: 'nav.cattle.all',
icon: 'icon icon-globe',
route: 'stacks',
ctx: [getProjectId],
queryParams: {which: C.EXTERNAL_ID.KIND_ALL, tags: ''},
condition: isOwner,
},
{ divider: true ,
condition: isOwner,
},
{
id: 'cattle-user',
localizedLabel: 'nav.cattle.user',
icon: 'icon icon-layers',
route: 'stacks',
ctx: [getProjectId],
queryParams: {which: C.EXTERNAL_ID.KIND_USER, tags: ''},
condition: isOwner,
},
{
id: 'cattle-infra',
localizedLabel: 'nav.cattle.system',
icon: 'icon icon-gear',
route: 'stacks',
ctx: [getProjectId],
condition: isOwner,
queryParams: {which: C.EXTERNAL_ID.KIND_INFRA, tags: ''},
}
];
let stacks = this.get('store').all('stack');
let choices = uniqKeys(tagChoices(stacks));
if ( choices.length ) {
out.push({divider: true});
choices.forEach((choice) => {
out.push({
id: 'cattle-tag-'+choice,
label: choice,
icon: 'icon icon-tag',
route: 'stacks',
ctx: [getProjectId],
condition: isOwner,
queryParams: {which: C.EXTERNAL_ID.KIND_ALL, tags: choice},
});
});
}
return out;
}
function getCatalogSubtree() {
let repos = getCatalogNames(this.get(`settings.${C.SETTING.CATALOG_URL}`));
let showAll = repos.length > 1;

View File

@ -1117,6 +1117,7 @@ stacksPage:
all: All Stacks
user: User Stacks
custom: '{name} Stacks'
tags: '"{tags}" Stacks'
infra: Infrastructure Stacks
actionButton: Add Stack
catalogButton: Add from Catalog
@ -1670,7 +1671,7 @@ editStack:
group:
label: Tags
placeholder: e.g. frontend, production
help: The stacks list can be filtered by tags (comma-separated)
help: Comma-separated list of tags. The Stacks list can be filtered by individual tags.
stackHeader:
backLink: "Stack:"