This commit is contained in:
Vincent Fiduccia 2017-05-07 22:58:42 -07:00
parent 4866922a4f
commit 7a9a414b4a
No known key found for this signature in database
GPG Key ID: 2B29AD6BB2BB2582
20 changed files with 221 additions and 138 deletions

View File

@ -15,7 +15,7 @@
fullRows=true
groupByKey=(if simpleMode null "stack.id")
groupByRef="stack"
pagingLabel="pagination.container"
pagingLabel="pagination.loadBalancers"
subHeaders=containerHeaders
subSearchField="instances"
headers=headers as |sortable kind inst dt|}}

View File

@ -7,7 +7,10 @@ const NOTCONFIGURED = 'notConfigured';
const CONFIGURED = 'configured';
const COUNTCONFIGURED = 'countConfigured';
const STANDARD = 'standard';
const SPECIFIC = 'specific';
const CUSTOM = 'custom';
const RULE = 'rule';
const ANY = 'any';
export const STATUS = {
NONE,
@ -17,7 +20,10 @@ export const STATUS = {
CONFIGURED,
COUNTCONFIGURED,
STANDARD,
CUSTOM
CUSTOM,
SPECIFIC,
RULE,
ANY
}
export const STATUS_INTL_KEY = 'accordionRow.status';
@ -27,6 +33,7 @@ export function classForStatus(status) {
case NONE:
case NOTCONFIGURED:
case STANDARD:
case ANY:
return 'text-muted';
case INCOMPLETE:
case ERROR:

View File

@ -1,7 +1,10 @@
import Ember from 'ember';
import ManageLabels from 'ui/mixins/manage-labels';
import { STATUS, STATUS_INTL_KEY, classForStatus } from 'ui/components/accordion-row/component';
export default Ember.Component.extend(ManageLabels, {
intl: Ember.inject.service(),
// Inputs
// Global scale scheduling
isGlobal: false,
@ -130,4 +133,22 @@ export default Ember.Component.extend(ManageLabels, {
return list.sortBy('name','id');
}.property('allHosts.@each.{id,name,state}'),
statusClass: null,
status: function() {
let k = STATUS.ANY;
let count = this.get('labelArray').filterBy('type','affinity').length;
if ( this.get('isRequestedHost') ) {
k = STATUS.SPECIFIC;
} else if ( count ) {
if ( this.get('errors.length') ) {
k = STATUS.INCOMPLETE;
} else {
k = STATUS.RULE;
}
}
this.set('statusClass', classForStatus(k));
return this.get('intl').t(`${STATUS_INTL_KEY}.${k}`, {count: count});
}.property('isRequestedHost','labelArray.@each.type','errors.length'),
});

View File

@ -100,16 +100,20 @@ export default Ember.Component.extend(NewOrEdit, SelectTab, {
},
removeSidekick(idx) {
var ary = this.get('service.secondaryLaunchConfigs');
var ary = this.get('primaryService.secondaryLaunchConfigs');
ary.removeAt(idx);
},
},
init() {
window.nec = this;
this._super(...arguments);
// Tell cattle that we're sending the whole thing, not a diff.
if ( this.get('service') ) {
this.set('service.completeLaunchConfigs', true);
}
if ( !this.get('launchConfig.secrets') ) {
this.set('launchConfig.secrets', []);
}
@ -260,7 +264,7 @@ export default Ember.Component.extend(NewOrEdit, SelectTab, {
}
}
return false;
return ok;
},
didSave() {
@ -301,16 +305,6 @@ export default Ember.Component.extend(NewOrEdit, SelectTab, {
return k;
}.property('isUpgrade','isService'),
nameToken: function() {
let k = 'newContainer.name.label.';
if ( this.get('isService') ) {
k += 'service';
} else {
k += 'container';
}
return k;
}.property('isService'),
supportsSecrets: function() {
return !!this.get('store').getById('schema','secret');
}.property(),

View File

@ -1,12 +1,16 @@
<section class="header clearfix">
<h1>{{t headerToken name=primaryResource.name}}</h1>
{{#if isSidekick}}
<div class="right-buttons">
<button class="btn bg-transparent" {{action "removeSidekick" launchConfigIndex}}>{{t 'newContainer.removeSidekick'}}</button>
</div>
{{/if}}
</section>
<div class="row">
<div class="col span-11-of-24">
{{form-name-description
model=primaryResource
nameLabel=nameToken
namePlaceholder="newContainer.name.placeholder"
descriptionPlaceholder="newContainer.description.placeholder"
rowClass=""
@ -87,7 +91,7 @@
</div>
</div>
{{#advanced-section advanced=false}}
{{#if (and isService (not isSidekick))}}
{{container/form-scheduling
isService=isService
isGlobal=isGlobal
@ -99,13 +103,31 @@
setGlobal=(action 'setGlobal')
setRequestedHost=(action 'setRequestedHostId')
}}
{{/if}}
{{form-healthcheck
{{form-healthcheck
classNames="accordion-wrapper"
isService=isService
healthCheck=launchConfig.healthCheck
errors=healthCheckErrors
editing=true
}}
{{#advanced-section advanced=false}}
{{container/form-command
classNames="accordion-wrapper"
instance=launchConfig
initialLabels=launchConfig.labels
errors=commandErrors
isService=isService
healthCheck=launchConfig.healthCheck
errors=healthCheckErrors
editing=true
setLabels=(action 'setLabels' 'command')
}}
{{form-user-labels
classNames="accordion-wrapper"
initialLabels=launchConfig.labels
setLabels=(action 'setLabels' 'user')
}}
{{#if isService}}
@ -123,40 +145,6 @@
{{/if}}
{{form-user-labels
classNames="accordion-wrapper"
initialLabels=launchConfig.labels
setLabels=(action 'setLabels' 'user')
}}
{{#if supportsSecrets}}
{{container/form-secrets
classNames="accordion-wrapper"
secrets=launchConfig.secrets
errors=secretErrors
editing=true
}}
{{/if}}
{{container/form-command
classNames="accordion-wrapper"
instance=launchConfig
initialLabels=launchConfig.labels
errors=commandErrors
isService=isService
setLabels=(action 'setLabels' 'command')
}}
{{container/form-volumes
classNames="accordion-wrapper"
instance=launchConfig
isService=isService
service=service
primaryService=primaryService
launchConfigIndex=launchConfigIndex
errors=volumeErrors
}}
{{container/form-networking
editing=true
instance=launchConfig
@ -169,12 +157,31 @@
setLabels=(action 'setLabels' 'networking')
}}
{{#if supportsSecrets}}
{{container/form-secrets
classNames="accordion-wrapper"
secrets=launchConfig.secrets
errors=secretErrors
editing=true
}}
{{/if}}
{{container/form-security
instance=launchConfig
errors=securityErrors editing=true
initialLabels=launchConfig.labels
setLabels=(action 'setLabels' 'security')
}}
{{container/form-volumes
classNames="accordion-wrapper"
instance=launchConfig
isService=isService
service=service
primaryService=primaryService
launchConfigIndex=launchConfigIndex
errors=volumeErrors
}}
{{/advanced-section}}
{{#if (and isService (not isSidekick))}}

View File

@ -15,16 +15,18 @@ function modeToType(mode) {
}
export default Ember.Component.extend(NewOrEdit, {
intl: Ember.inject.service(),
record: null,
editing: true,
classNames: ['inline-form'],
primaryResource: Ember.computed.alias('record'),
mode: null,
targetServicesMap: null,
targetServicesAsMaps: null,
targetIpArray: null,
stack: null,
stackErrors: null,
actions: {
done() {
@ -36,7 +38,7 @@ export default Ember.Component.extend(NewOrEdit, {
},
setTargetServices(array, resources) {
this.set('targetServicesMap', resources);
this.set('targetServicesAsMaps', resources);
},
addTargetIp() {
@ -63,10 +65,15 @@ export default Ember.Component.extend(NewOrEdit, {
this.set('mode', mode);
this.set('targetServicesMap',[]);
this.set('targetServicesAsMaps',[]);
this.set('targetIpArray',[]);
},
canHealthCheck: function() {
let mode = this.get('mode');
return (mode === IP) || (mode === HOSTNAME);
}.property('mode'),
modeChanged: function() {
let mode = this.get('mode');
let type = modeToType(mode);
@ -75,22 +82,39 @@ export default Ember.Component.extend(NewOrEdit, {
this.set('record', neu);
}.observes('mode'),
targetIpArrayChanged: function() {
this.set('record.externalIpAddresses', this.get('targetIpArray').map((x) => x.value).filter((x) => !!x));
}.observes('targetIpArray.@each.value'),
validate() {
let errors = this._super(...arguments);
this._super(...arguments);
let errors = this.get('errors')||[];
switch ( this.get('mode') ) {
case HOSTNAME:
if ( !this.get('model.hostname') ) {
return false;
if ( !this.get('record.hostname') ) {
errors.pushObject(this.get('intl').t('editDns.errors.hostnameRequired'));
}
break;
case ALIAS:
if ( !this.get('targetServicesAsMaps.length') ) {
errors.pushObject(this.get('intl').t('editDns.errors.serviceRequired'));
}
break;
case IP:
if ( !this.get('record.externalIpAddresses.length') ) {
errors.pushObject(this.get('intl').t('editDns.errors.ipRequired'));
}
break;
case SELECTOR:
if ( !this.get('record.selectorContainer.length') ) {
errors.pushObject(this.get('intl').t('editDns.errors.selectorRequired'));
}
break;
}
errors.pushObjects(this.get('stackErrors')||[]);
this.set('errors', errors);
return errors.length === 0;
},
@ -102,13 +126,24 @@ export default Ember.Component.extend(NewOrEdit, {
this.set('record.externalIpAddresses', null);
}
return true;
if ( !this.get('id') ) {
// Set the stack ID
if ( this.get('stack.id') ) {
this.set('record.stackId', this.get('stack.id'));
} else if ( this.get('stack') ) {
return this.get('stack').save().then((newStack) => {
this.set('record.stackId', newStack.get('id'));
});
}
}
return this._super(...arguments);
},
didSave() {
if ( this.get('mode') === ALIAS ) {
return this.get('record').doAction('setservicelinks', {
serviceLinks: this.get('targetServicesMap'),
serviceLinks: this.get('targetServicesAsMaps'),
});
}
},

View File

@ -3,11 +3,27 @@
</section>
<section class="horizontal-form container-fluid">
{{form-name-description
model=record
namePlaceholder="editDns.name.placeholder"
descriptionPlaceholder="editDns.description.placeholder"
}}
<div class="row">
<div class="col span-11-of-24">
{{form-name-description
model=record
namePlaceholder="editDns.name.placeholder"
nameRequired=true
descriptionPlaceholder="editDns.description.placeholder"
rowClass=""
colClass=""
bothColClass=""
}}
</div>
<div class="col span-11-of-24 offset-1-of-24">
{{#unless editing}}
{{form-stack
stack=stack
errors=stackErrors
}}
{{/unless}}
</div>
</div>
<div class="row">
<div class="col span-6">
@ -41,7 +57,7 @@
{{else if (or (eq mode "externalip") (eq mode "externalhostname"))}}
{{#if (eq mode "externalip")}}
<div class="mb-20">
<label>{{t 'editDns.targetIp.label'}}</label>
<label>{{t 'editDns.targetIp.label'}}{{field-required}}</label>
</div>
<div>
<button class="btn bg-link icon-btn" {{action "addTargetIp"}}>
@ -71,13 +87,13 @@
{{/if}}
{{else}}
<div class="mb-20">
<label>{{t 'editDns.hostname.label'}}</label>
<label>{{t 'editDns.hostname.label'}}{{field-required}}</label>
</div>
{{input value=record.hostname placeholder=(t 'editDns.hostname.placeholder')}}
{{/if}}
{{else}}
<div class="mb-20">
<label>{{t 'editDns.selectorContainer.label'}}</label>
<label>{{t 'editDns.selectorContainer.label'}}{{field-required}}</label>
</div>
{{input value=record.selectorContainer placeholder=(t 'editDns.selectorContainer.placeholder')}}
{{/if}}
@ -86,15 +102,13 @@
</div>
</section>
{{#if (or (eq mode "externalip") (eq mode "externalhostname"))}}
<section class="box mt-20">
{{form-healthcheck
isService=true
showStrategy=false
healthCheck=record.healthCheck
}}
<div class="alert alert-info">{{t 'editDns.healthCheckNote'}}</div>
</section>
{{#if canHealthCheck}}
{{form-healthcheck
isService=true
showStrategy=false
healthCheck=record.healthCheck
dnsNote=true
}}
{{/if}}
{{top-errors errors=errors}}

View File

@ -32,6 +32,7 @@ export default Ember.Component.extend({
errors: null,
isService: null,
showStrategy: true,
dnsNote: false,
editing: true,

View File

@ -1,6 +1,6 @@
{{#accordion-row
title=(t 'formHealthCheck.title')
detail=(t 'formHealthCheck.detail' appName=settings.appName)
detail=(t (if dnsNote 'formHealthCheck.detailDns' 'formHealthCheck.detail') appName=settings.appName)
status=status
statusClass=statusClass
}}

View File

@ -1,5 +1,5 @@
<div class="mb-20">
<label>{{t 'formTargets.title'}}</label>
<label>{{t 'formTargets.title'}}{{field-required}}</label>
</div>
<div>
<button class="btn bg-link icon-btn" {{action "addTargetService"}}>

View File

@ -18,23 +18,25 @@ export default Ember.Component.extend(ModalBase, NewOrEdit, {
this.set('justCreated', false);
},
isAccount: Ember.computed.equal('model.accountId','projects.current.id'),
isEnvironment: function() {
return this.get('model.accountId') === this.get('projects.current.id');
}.property('model.accountId','projects.current.id'),
displayEndpoint: function() {
if ( this.get('isAccount') ) {
return this.get('endpointService.api.display.account.current');
} else {
if ( this.get('isEnvironment') ) {
return this.get('endpointService.api.display.environment.current');
} else {
return this.get('endpointService.api.display.account.current');
}
}.property('isAccount'),
}.property('isEnvironment'),
linkEndpoint: function() {
if ( this.get('isAccount') ) {
return this.get('endpointService.api.auth.account.current');
} else {
if ( this.get('isEnvironment') ) {
return this.get('endpointService.api.auth.environment.current');
} else {
return this.get('endpointService.api.auth.account.current');
}
}.property('model.accountId'),
}.property('isEnvironment'),
didInsertElement() {
setTimeout(() => {

View File

@ -4,7 +4,7 @@
<p>
<label>{{t 'apiPage.currentEndpoint'}}</label>
<div style="font-size: 150%;">
<div class="btn bg-transparent" style="font-size: 150%;">
<code>
<a href="{{linkEndpoint}}" target="_blank" rel="nofollow noreferer">{{displayEndpoint}}</a>
{{copy-to-clipboard clipboardText=linkEndpoint size="sm"}}

View File

@ -15,7 +15,7 @@
fullRows=true
groupByKey=(if simpleMode null "stack.id")
groupByRef="stack"
pagingLabel="pagination.container"
pagingLabel="pagination.dnsRecord"
subHeaders=containerHeaders
subSearchField="instances"
headers=headers as |sortable kind inst dt|}}

View File

@ -6,6 +6,12 @@ const USER = 'user';
const SYSTEM = 'system';
const AFFINITY = 'affinity';
export const TYPE = {
USER,
SYSTEM,
AFFINITY
}
export function flattenLabelArrays(...lists) {
let out = {};

View File

@ -5,7 +5,6 @@ import Errors from 'ui/utils/errors';
export default Ember.Mixin.create({
originalModel: null,
errors: null,
saving: false,
editing: true,
primaryResource: Ember.computed.alias('model'),
originalPrimaryResource: Ember.computed.alias('originalModel'),
@ -13,13 +12,11 @@ export default Ember.Mixin.create({
initFields: function() {
this._super();
this.set('errors',null);
this.set('saving',false);
},
didReceiveAttrs: function() {
this._super();
this.set('errors',null);
this.set('saving',false);
},
validate: function() {
@ -69,8 +66,6 @@ export default Ember.Mixin.create({
this.errorSaving(err);
}).finally(() => {
try {
this.set('saving',false);
if ( cb )
{
cb();
@ -87,20 +82,7 @@ export default Ember.Mixin.create({
willSave: function() {
this.set('errors',null);
var ok = this.validate();
if ( !ok )
{
// Validation failed
return false;
}
if ( this.get('saving') )
{
// Already saving
return false;
}
this.set('saving',true);
return true;
return ok;
},
doSave: function(opt) {

View File

@ -1,11 +1,6 @@
import Ember from 'ember';
import Service from 'ui/models/service';
var DnsService = Service.extend({
export default Service.extend({
type: 'dnsService',
intl: Ember.inject.service(),
healthState: 'healthy',
});
export default DnsService;

View File

@ -1,12 +1,8 @@
import Service from 'ui/models/service';
var ExternalService = Service.extend({
export default Service.extend({
type: 'externalService',
healthState: function() {
return 'healthy';
}.property(),
displayTargets: function() {
let hostname = this.get('hostname');
if ( hostname ) {
@ -16,5 +12,3 @@ var ExternalService = Service.extend({
return (this.get('externalIpAddresses')||[]).join(', ');
}.property('hostname','externalIpAddresses')
});
export default ExternalService;

View File

@ -25,7 +25,7 @@ var Service = Resource.extend(StateCounts, {
}),
actions: {
edit() {
editDns() {
this.get('modalService').toggleModal('modal-edit-dns', this);
},
@ -154,13 +154,15 @@ var Service = Resource.extend(StateCounts, {
var canUpgrade = !!a.upgrade && this.get('canUpgrade');
var isK8s = this.get('isK8s');
var isSwarm = this.get('isSwarm');
var isReal = this.get('isReal');
var canHaveContainers = this.get('canHaveContainers');
var containerForShell = this.get('containerForShell');
var isDriver = ['networkdriverservice','storagedriverservice'].includes(this.get('lcType'));
var choices = [
{ label: 'action.upgradeOrEdit', icon: 'icon icon-arrow-circle-up', action: 'upgrade', enabled: canUpgrade },
{ label: 'action.rollback', icon: 'icon icon-history', action: 'rollback', enabled: !!a.rollback },
{ label: 'action.edit', icon: 'icon icon-pencil', action: 'editDns', enabled: !isReal },
{ label: 'action.rollback', icon: 'icon icon-history', action: 'rollback', enabled: !!a.rollback && isReal },
{ label: 'action.clone', icon: 'icon icon-copy', action: 'clone', enabled: !isK8s && !isSwarm && !isDriver },
{ divider: true },
{ label: 'action.execute', icon: 'icon icon-terminal', action: 'shell', enabled: !!containerForShell, altAction:'popoutShell'},
@ -171,14 +173,16 @@ var Service = Resource.extend(StateCounts, {
{ label: 'action.restart', icon: 'icon icon-refresh', action: 'restart', enabled: !!a.restart && canHaveContainers, bulkable: true },
{ label: 'action.stop', icon: 'icon icon-stop', action: 'promptStop', enabled: !!a.deactivate, altAction: 'deactivate', bulkable: true},
{ divider: true },
{ label: 'action.garbageCollect', icon: '', action: 'garbageCollect', enabled: !!a.garbagecollect},
{ label: 'action.garbageCollect', icon: '', action: 'garbageCollect', enabled: !!a.garbagecollect && isReal},
{ label: 'action.remove', icon: 'icon icon-trash', action: 'promptDelete', enabled: !!a.remove, altAction: 'delete', bulkable: true},
{ divider: true },
{ label: 'action.viewInApi', icon: 'icon icon-external-link', action: 'goToApi', enabled: true },
];
return choices;
}.property('actionLinks.{activate,deactivate,pause,restart,update,remove,rollback,garbagecollect}','lcType','isK8s','isSwarm','canHaveContainers','canUpgrade','containerForShell'),
}.property('actionLinks.{activate,deactivate,pause,restart,update,remove,rollback,garbagecollect}',
'lcType','isK8s','isSwarm','canHaveContainers','canUpgrade','containerForShell'
),
serviceLinks: null, // Used for clone

View File

@ -15,7 +15,7 @@
fullRows=true
groupByKey=(if simpleMode null "stack.id")
groupByRef="stack"
pagingLabel="pagination.container"
pagingLabel="pagination.scalingGroup"
subHeaders=containerHeaders
subSearchField="instances"
headers=headers as |sortable kind inst dt|}}

View File

@ -575,7 +575,7 @@ editDns:
label: "Resolves To"
dnsservice: One or more other services
service: The set of containers which match a selector
externalip: One or more external IP Addresses
externalip: One or more external IP addresses
externalhostname: An external hostname
targetIp:
label: Target IP Addresses
@ -583,6 +583,11 @@ editDns:
hostname:
label: Target Hostname
placeholder: e.g. foobar.com
errors:
ipRequired: 'One or more "Target IP Addresses" are requried'
hostnameRequired: '"Target Hostname" is required'
serviceRequired: 'One or more "Targets" are required'
selectorRequired: '"Container Selector" is required'
# If you change translations here also change the translation in app/utils/constants.js under the FALLBACK_TRANSLATIONS key
@ -1572,6 +1577,9 @@ accordionRow:
countConfigured: "{count} Configured"
standard: Default
custom: Customized
specific: Specific
any: Any
rule: "{count, plural, =1 {# Rule} other {# Rules}}"
advancedSection:
showText: Show Advanced Options
@ -2057,6 +2065,7 @@ formEngineOpts:
formHealthCheck:
title: Health Check
detail: A health check allows {appName} to know if your container is healthy. For scaling groups, an unhealthy container can be automatically replaced.
detailDns: A health check allows {appName} to know if the external resource is healty or not. This will be used when this record is the target of a Load Balancer.
checkType:
none: None
tcp: Check that a TCP connection opens successfully
@ -2230,7 +2239,7 @@ formScale:
formScheduling:
title: Host Scheduling
detail: Choose what hosts containers will be deployed to
detail: Configure what hosts the containers can be deployed to.
status: |
{count, plural,
=0 {No rules}
@ -2348,7 +2357,7 @@ formSecurity:
formServiceLinks:
title: Links
detail: Define relationships between this scaling group and other services
detail: Define relationships between this scaling group and other services.
addAction: Add Link
noServices: There are no other services to link to.
noLinks: This service has no service links.
@ -3387,9 +3396,6 @@ newContainer:
addSidekick: Add a Sidekick
removeSidekick: Remove this Sidekick
name:
label:
container: Container Name
service: Service Name
placeholder: e.g. myapp
description:
placeholder: e.g. My Application
@ -3498,6 +3504,21 @@ pagination:
=0 {No Containers}
=1 {{count} {count, plural, =1 {Container} other {Containers}}}
other {{from} - {to} of {count} Containers}}
scalingGroup: |
{pages, plural,
=0 {No Scaling Groups}
=1 {{count} {count, plural, =1 {Scaling Group} other {Scaling Groups}}}
other {{from} - {to} of {count} Scaling Groups}}
loadBalancers: |
{pages, plural,
=0 {No Load Balancers}
=1 {{count} {count, plural, =1 {Load Balancer} other {Load Balancers}}}
other {{from} - {to} of {count} Load Balancers}}
dnsRecord: |
{pages, plural,
=0 {No DNS Records}
=1 {{count} {count, plural, =1 {DNS Record} other {DNS Records}}}
other {{from} - {to} of {count} DNS Records}}
port: |
{pages, plural,
=0 {No Ports}