Merge branch 'master' of github.com:hubert-he/ui

This commit is contained in:
zhenhua he 2019-11-13 14:47:17 +08:00
commit 106de7be6b
23 changed files with 352 additions and 170 deletions

View File

@ -26,7 +26,8 @@ export default Route.extend({
let agent = window.navigator.userAgent.toLowerCase();
if ( agent.indexOf('msie ') >= 0 || agent.indexOf('trident/') >= 0 ) {
// Show the we don't support internet explorer or edge browsers (only edge html based browsers the mobile and chromium based browsers should be okay).
if ( agent.indexOf('msie ') >= 0 || agent.indexOf('trident/') >= 0 || agent.indexOf('edge/') >= 0) {
this.replaceWith('ie');
return;

View File

@ -61,7 +61,6 @@ export default Component.extend({
lastScrollTop = scrollTop;
});
this.exec();
var btn = $('.scroll-bottom')[0]; // eslint-disable-line
if ( btn ) {

View File

@ -2,5 +2,5 @@
<br><br>
<div class="sad-ie"></div>
<br><br>
<h3s>Sorry, IE is not supported.</h3s>
<h3s>Sorry, IE and Edge are not supported.</h3s>
</section>

View File

@ -57,7 +57,7 @@ export default Resource.extend({
return out;
}),
validationErrors() {
validationErrors(answersMap) {
const {
intl, allQuestions, valuesYaml
} = this;
@ -96,7 +96,7 @@ export default Resource.extend({
} else {
if ( filteredQuestions ) {
filteredQuestions.forEach((item) => {
if ( item.required && item.type !== 'boolean' && !item.answer ) {
if ( item.required && item.type !== 'boolean' && isEmpty(answersMap[item.variable]) ) {
errors.push(intl.t('validation.required', { key: item.label }));
}

View File

@ -205,6 +205,11 @@
white-space: normal;
}
.list-small {
line-height: 14px;
padding: 0 0 0 22px;
margin: 0;
}
.list-unstyled { @include list-unstyled }
.no-select { @include no-select }
.no-resize { @include no-resize }

View File

@ -112,7 +112,7 @@ select {
&:hover {
border-color: $input-bg-hover;
background: rgba($input-bg-hover, .2);
background-color: rgba($input-bg-hover, .2);
&::placeholder {
color: rgba($input-color-placeholder, .35);
}
@ -126,7 +126,7 @@ select {
}
}
&:focus {
background: rgba($input-border-focus, .2);
background-color: rgba($input-border-focus, .2);
border-color: $input-border-focus;
transition: ease-in-out all .25s;
&::placeholder {

View File

@ -13,7 +13,6 @@
white-space: -pre-wrap;
white-space: -o-pre-wrap;
word-wrap: break-word;
width: auto;
}
}

View File

@ -89,6 +89,7 @@ export default Component.extend(NewOrEdit, CatalogApp, {
selectedTemplateUrl: null,
multiClusterApp: { targets: [], },
},
mcAppIsSaving: false,
overridesHeaders: OVERRIDE_HEADERS,
@ -277,6 +278,10 @@ export default Component.extend(NewOrEdit, CatalogApp, {
},
updateAnswerOverrides: observer('selectedTemplateModel', 'multiClusterApp.answers.@each.{values}', function() {
if (this.mcAppSaving) {
return;
}
let { selectedTemplateModel = {} } = this;
const questions = get(selectedTemplateModel, 'questions')
@ -363,7 +368,7 @@ export default Component.extend(NewOrEdit, CatalogApp, {
}
}),
templateOrHelmChartQuestions: computed('selectedTemplateModel', function() {
templateOrHelmChartQuestions: computed('selectedTemplateModel', 'selectedTemplateModel.allQuestions.@each.{answer,variable}', function() {
let { selectedTemplateModel, multiClusterApp } = this;
let nueQuestions = [];
@ -587,7 +592,7 @@ export default Component.extend(NewOrEdit, CatalogApp, {
this._super(...arguments);
const errors = get(this, 'errors') || [];
errors.pushObjects(get(this, 'selectedTemplateModel').validationErrors() || []);
errors.pushObjects(get(this, 'selectedTemplateModel').validationErrors(this.answers) || []);
errors.pushObjects(this.validateTargetsProjectIds());
set(this, 'errors', errors.uniq());

View File

@ -408,6 +408,7 @@
{{save-cancel
createLabel=(if editing saveUpgrade saveNew)
save=(action "save")
saving=mcAppSaving
cancel=(action "cancel")
}}
</div>

View File

@ -135,6 +135,7 @@ export default Component.extend(NodeDriver, {
this.initCustomAttributes();
this.initTag();
this.initNetwork();
this.initUseDataStoreCluster();
},
actions: {
@ -166,6 +167,12 @@ export default Component.extend(NodeDriver, {
return keyContent.filter((keyContent) => {
return keyValuePairs.findIndex((kvp) => kvp.key === keyContent.value) === -1;
});
},
toggleUseDataStoreCluster(value) {
set(this, 'config.useDataStoreCluster', value);
const clearKey = value ? 'config.datastore' : 'config.datastoreCluster';
set(this, clearKey, '');
}
},
@ -236,6 +243,16 @@ export default Component.extend(NodeDriver, {
return this.mapPathOptionsToContent(options);
}),
dataStoreClusterContent: computed('config.datacenter', async function() {
const options = await this.requestOptions(
'data-store-clusters',
get(this, 'model.cloudCredentialId'),
get(this, 'config.datacenter')
);
return this.mapPathOptionsToContent(options);
}),
folderContent: computed('config.datacenter', async function() {
const options = await this.requestOptions(
'folders',
@ -324,6 +341,7 @@ export default Component.extend(NodeDriver, {
let config = get(this, 'globalStore').createRecord({
type: CONFIG,
useDataStoreCluster: false,
cpuCount: '2',
memorySize: '2048',
diskSize: '20000',
@ -406,6 +424,17 @@ export default Component.extend(NodeDriver, {
}
},
initUseDataStoreCluster() {
const useDataStoreCluster = !!get(this, 'config.datastoreCluster');
set(this, 'config.useDataStoreCluster', useDataStoreCluster);
// Only one should be set at a time
const clearKey = useDataStoreCluster ? 'config.datastore' : 'config.datastoreCluster';
set(this, clearKey, '');
},
updateVappOptions(opts) {
set(this, 'config.vappIpprotocol', opts.vappIpprotocol);
set(this, 'config.vappIpallocationpolicy', opts.vappIpallocationpolicy);
@ -418,6 +447,13 @@ export default Component.extend(NodeDriver, {
const configCustomAttribute = get(this, 'customAttribute').map((kvp) => `${ kvp.key }=${ kvp.value }`);
set(this, 'config.customAttribute', configCustomAttribute);
const clearKey = get(this, 'config.useDataStoreCluster')
? 'config.datastore'
: 'config.datastoreCluster';
set(this, clearKey, '');
const vappMode = get(this, 'vappMode')
if (vappMode === VAPP_MODE_DISABLED) {

View File

@ -49,6 +49,7 @@
<p class="help-block">
{{t "nodeDriver.vmwarevsphere.dataCenter.help"}}
</p>
<SelectValueCheck @values={{config.datacenter}} @options={{datacenterContent}} />
</div>
<div class="col span-6">
@ -64,6 +65,7 @@
<p class="help-block">
{{t "nodeDriver.vmwarevsphere.pool.help"}}
</p>
<SelectValueCheck @values={{config.pool}} @options={{resourcePoolContent}} />
</div>
</div>
@ -71,16 +73,41 @@
<div class="col span-6">
<label class="acc-label">
{{t "nodeDriver.vmwarevsphere.dataStore.label"}}
<TooltipElement
@type="tooltip-basic"
@tooltipTemplate="tooltip-static"
@model={{t "nodeDriver.vmwarevsphere.dataStore.cluster.tooltip"}}
@inlineBlock={{true}}
>
<BtnToggle
@toggled={{action "toggleUseDataStoreCluster"}}
@checked={{mut config.useDataStoreCluster}}
/>
</TooltipElement>
</label>
<NewSelect
@class="form-control"
@useContentForDefaultValue={{true}}
@content={{dataStoreContent}}
@value={{config.datastore}}
/>
<p class="help-block">
{{t "nodeDriver.vmwarevsphere.dataStore.help"}}
</p>
{{#if config.useDataStoreCluster}}
<NewSelect
@class="form-control"
@useContentForDefaultValue={{true}}
@content={{dataStoreClusterContent}}
@value={{config.datastoreCluster}}
/>
<p class="help-block">
{{t "nodeDriver.vmwarevsphere.dataStore.cluster.help"}}
</p>
<SelectValueCheck @values={{config.datastoreCluster}} @options={{dataStoreClusterContent}} />
{{else}}
<NewSelect
@class="form-control"
@useContentForDefaultValue={{true}}
@content={{dataStoreContent}}
@value={{config.datastore}}
/>
<p class="help-block">
{{t "nodeDriver.vmwarevsphere.dataStore.help"}}
</p>
<SelectValueCheck @values={{config.datastore}} @options={{dataStoreContent}} />
{{/if}}
</div>
<div class="col span-6">
<label class="acc-label">
@ -95,6 +122,7 @@
<p class="help-block">
{{t "nodeDriver.vmwarevsphere.folder.help"}}
</p>
<SelectValueCheck @values={{config.folder}} @options={{folderContent}} />
</div>
</div>
@ -112,6 +140,7 @@
<p class="help-block">
{{t "nodeDriver.vmwarevsphere.host.help"}}
</p>
<SelectValueCheck @values={{config.hostsystem}} @options={{hostContent}} />
</div>
</div>
{{/accordion-list-item}}
@ -274,6 +303,7 @@
@valueLabel="nodeDriver.vmwarevsphere.network.valueLabel"
@valuePlaceholder="nodeDriver.vmwarevsphere.network.valuePlaceholder"
/>
<SelectValueCheck @values={{config.network}} @options={{networkContent}} />
</div>
</div>

View File

@ -1,6 +1,8 @@
{{#if applyClusterTemplate}}
{{#if (has-override questions=questions paramName=paramName)}}
{{yield}}
{{yield (hash
hasOverride=true
)}}
{{else}}
<div>
{{#if value}}

View File

@ -1,15 +1,15 @@
import Component from '@ember/component'
import ClusterDriver from 'shared/mixins/cluster-driver';
import layout from './template';
import {
get, set, computed, observer, setProperties
} from '@ember/object';
import { sortableNumericSuffix } from 'shared/utils/util';
import { reject, all } from 'rsvp';
import { inject as service } from '@ember/service';
import { equal } from '@ember/object/computed'
import { equal } from '@ember/object/computed';
import $ from 'jquery';
import { isEmpty } from '@ember/utils';
const times = [
{
@ -211,19 +211,21 @@ export default Component.extend(ClusterDriver, {
if ( !config ) {
config = get(this, 'globalStore').createRecord({
type: 'googleKubernetesEngineConfig',
diskSizeGb: 100,
enableAlphaFeature: false,
nodeCount: 3,
machineType: 'n1-standard-2',
zone: 'us-central1-f',
clusterIpv4Cidr: '',
minNodeCount: 1,
maxNodeCount: 5,
imageType: 'UBUNTU',
diskType: 'pd-standard',
region: 'us-west2',
taints: [],
type: 'googleKubernetesEngineConfig',
diskSizeGb: 100,
enableAlphaFeature: false,
nodeCount: 3,
machineType: 'n1-standard-2',
zone: 'us-central1-f',
clusterIpv4Cidr: '',
minNodeCount: 1,
maxNodeCount: 5,
imageType: 'UBUNTU',
diskType: 'pd-standard',
region: 'us-west2',
taints: [],
useIpAliases: true,
ipPolicyCreateSubnetwork: true,
});
setProperties(this, {
@ -448,8 +450,14 @@ export default Component.extend(ClusterDriver, {
const subNetworkContent = get(this, 'subNetworkContent') || []
if (subNetworkContent.length > 0) {
set(this, 'config.subNetwork', subNetworkContent[0] && subNetworkContent[0].value)
if (subNetworkContent.length > 1) {
const firstNonNullSubnetMatch = subNetworkContent.find((sn) => !isEmpty(sn.value));
setProperties(this, {
'config.subNetwork': firstNonNullSubnetMatch.value,
'config.ipPolicyCreateSubnetwork': false,
})
const secondaryIpRangeContent = get(this, 'secondaryIpRangeContent') || []
if (secondaryIpRangeContent.length > 0) {
@ -463,6 +471,20 @@ export default Component.extend(ClusterDriver, {
}
}),
subnetworkChange: observer('config.subNetwork', function() {
if (this.saving) {
return;
}
const { config: { subNetwork } } = this;
if (isEmpty(subNetwork)) {
set(this, 'config.ipPolicyCreateSubnetwork', true);
} else {
set(this, 'config.ipPolicyCreateSubnetwork', false);
}
}),
secondaryIpRangeContentChange: observer('secondaryIpRangeContent.[]', 'config.useIpAliases', function() {
if (this.saving) {
return;
@ -480,8 +502,15 @@ export default Component.extend(ClusterDriver, {
return;
}
if (!get(this, 'config.useIpAliases')) {
set(this, 'config.enablePrivateNodes', false)
if (get(this, 'config.useIpAliases')) {
if (!isEmpty(this.config.subNetwork)) {
set(this, 'config.ipPolicyCreateSubnetwork', false);
}
} else {
setProperties(this, {
'config.enablePrivateNodes': false,
'config.ipPolicyCreateSubnetwork': false,
});
}
}),
@ -544,43 +573,62 @@ export default Component.extend(ClusterDriver, {
return zoneChoices.filter((z) => (z.name || '').startsWith(locationName) && z.name !== zone)
}),
networkContent: computed('networks', function() {
networkContent: computed('networks', 'config.zone', function() {
return get(this, 'networks')
}),
subNetworkContent: computed('subNetworks.[]', 'config.network', function() {
const subNetworks = get(this, 'subNetworks') || []
const networkName = get(this, 'config.network')
subNetworkContent: computed('subNetworks.[]', 'config.network', 'config.zone', function() {
const {
config: { network: networkName },
networkContent,
subNetworks = [],
} = this;
const out = subNetworks.filter((s) => {
const { network = '' } = s
const arr = network.split('/') || []
const networkDisplayName = arr[arr.length - 1]
const filteredSubnets = (subNetworks || []).filter((s) => {
const network = networkContent.findBy('selfLink', s.network);
const networkDisplayName = network.name;
if (networkDisplayName === networkName) {
return true
}
})
});
const mappedSubnets = filteredSubnets.map((o) => {
const network = networkContent.findBy('selfLink', o.network);
const networkDisplayName = network.name;
return out.map((o) => {
return {
label: `${ o.name }(${ o.ipCidrRange })`,
value: o.name,
secondaryIpRanges: o.secondaryIpRanges,
networkDisplayName
}
})
});
const defaultSubnetAry = [{
label: this.intl.t('clusterNew.googlegke.ipPolicyCreateSubnetwork.autoLabel'),
value: '',
}];
return [...defaultSubnetAry, ...mappedSubnets];
}),
secondaryIpRangeContent: computed('subNetworkContent.[]', 'config.network', function() {
const subNetworkContent = get(this, 'subNetworkContent')
const { secondaryIpRanges = [] } = subNetworkContent
const { subNetworkContent = [], config: { network } } = this;
const subNetwork = subNetworkContent.findBy('networkDisplayName', network);
return secondaryIpRanges.map((s) => {
return {
lable: `${ s.rangeName }(${ s.ipCidrRange })`,
value: s.rangeName,
}
})
if (subNetwork) {
const { secondaryIpRanges = [] } = subNetwork;
return secondaryIpRanges.map((s) => {
return {
label: `${ s.rangeName }(${ s.ipCidrRange })`,
value: s.rangeName,
}
});
}
return [];
}),
serviceAccountContent: computed('serviceAccounts', function() {
@ -593,6 +641,24 @@ export default Component.extend(ClusterDriver, {
return get(this, 'maintenanceWindowTimes').findBy('value', get(this, 'config.maintenanceWindow')) || { label: 'Any Time' };
}),
shouldAllowDisableCreateSubNetwork: computed('config.subNetwork', function() {
const {
config: { subNetwork },
secondaryIpRangeContent,
editing,
} = this;
if (isEmpty(subNetwork)) {
return true;
}
if (editing && isEmpty(secondaryIpRangeContent)) {
return true;
}
return false;
}),
fetchZones() {
return get(this, 'globalStore').rawRequest({
url: '/meta/gkeZones',

View File

@ -315,14 +315,16 @@
selection=config.enableHorizontalPodAutoscaling
value=true
disabled=editing
}} {{t "generic.enabled"}}
}}
{{t "generic.enabled"}}
</label>
<label class={{concat (if editing "text-muted") " hand"}}>
{{radio-button
selection=config.enableHorizontalPodAutoscaling
value=false
disabled=editing
}} {{t "generic.disabled"}}
}}
{{t "generic.disabled"}}
</label>
</div>
</div>
@ -345,6 +347,7 @@
</div>
</div>
</div>
<div class="row">
<div class="col span-6">
<label class="acc-label">
@ -385,111 +388,85 @@
{{/if}}
</div>
{{#advanced-section advanced=clusterAdvanced}}
<h4 class="mt-20 mb-10">{{t "clusterNew.googlegke.header.iPAllocationPolicy"}}</h4>
<hr/>
<div class="row">
<div class="col span-6">
<label class="acc-label">
{{t "clusterNew.googlegke.useIpAliases.label"}}
<div class="row">
<div class="col span-6">
<label class="acc-label">
{{t "clusterNew.googlegke.useIpAliases.label"}}
</label>
<div class="form-control-static">
<label class={{concat (if editing "text-muted") " mr-20 hand"}}>
{{radio-button
selection=config.useIpAliases
value=true
disabled=editing
}}
{{t "generic.enabled"}}
</label>
<label class={{concat (if editing "text-muted") " hand"}}>
{{radio-button
selection=config.useIpAliases
value=false
disabled=(or editing (not config.subNetwork))
}}
{{t "generic.disabled"}}
</label>
<div class="form-control-static">
<label class={{concat (if editing "text-muted") " mr-20 hand"}}>
{{radio-button
selection=config.useIpAliases
value=true
disabled=editing
}}
{{t "generic.yes"}}
</label>
<label class={{concat (if editing "text-muted") " hand"}}>
{{radio-button
selection=config.useIpAliases
value=false
disabled=editing
}}
{{t "generic.no"}}
</label>
</div>
</div>
{{#if config.useIpAliases}}
</div>
</div>
{{#if config.useIpAliases}}
{{#if (and config.ipPolicyCreateSubnetwork config.useIpAliases)}}
<div class="row">
<div class="col span-6">
<label class="acc-label">
{{t "clusterNew.googlegke.ipPolicyCreateSubnetwork.label"}}
{{t "clusterNew.googlegke.ipPolicyClusterIpv4CidrBlock.label"}}
</label>
<div class="form-control-static">
<label class={{concat (if editing "text-muted") " mr-20 hand"}}>
{{radio-button
selection=config.ipPolicyCreateSubnetwork
value=true
disabled=editing
}}
{{t "generic.enabled"}}
</label>
<label class={{concat (if editing "text-muted") " hand"}} class={{concat (if (eq secondaryIpRangeContent.length 0) "text-muted") " hand"}}>
{{radio-button
selection=config.ipPolicyCreateSubnetwork
value=false
disabled=(or editing (eq secondaryIpRangeContent.length 0))
}}
{{t "generic.disabled"}}
</label>
</div>
{{input
value=config.ipPolicyClusterIpv4CidrBlock
placeholder=(t "clusterNew.googlegke.ipPolicyClusterIpv4CidrBlock.placeholder")
disabled=editing
}}
</div>
{{/if}}
</div>
{{#if config.useIpAliases}}
{{#if (and config.ipPolicyCreateSubnetwork config.useIpAliases)}}
<div class="row">
<div class="col span-6">
<label class="acc-label">
{{t "clusterNew.googlegke.ipPolicyClusterIpv4CidrBlock.label"}}
</label>
{{input
value=config.ipPolicyClusterIpv4CidrBlock
placeholder=(t "clusterNew.googlegke.ipPolicyClusterIpv4CidrBlock.placeholder")
disabled=editing
}}
</div>
<div class="col span-6">
<label class="acc-label">
{{t "clusterNew.googlegke.ipPolicyServicesIpv4CidrBlock.label"}}
</label>
{{input
value=config.ipPolicyServicesIpv4CidrBlock
placeholder=(t "clusterNew.googlegke.ipPolicyServicesIpv4CidrBlock.placeholder")
disabled=editing
}}
</div>
<div class="col span-6">
<label class="acc-label">
{{t "clusterNew.googlegke.ipPolicyServicesIpv4CidrBlock.label"}}
</label>
{{input
value=config.ipPolicyServicesIpv4CidrBlock
placeholder=(t "clusterNew.googlegke.ipPolicyServicesIpv4CidrBlock.placeholder")
disabled=editing
}}
</div>
{{else}}
<div class="row">
<div class="col span-6">
<label class="acc-label">
{{t "clusterNew.googlegke.ipPolicyClusterSecondaryRangeName.label"}}
</label>
{{searchable-select
content=secondaryIpRangeContent
classNames="form-control"
value=config.ipPolicyClusterSecondaryRangeName
disabled=editing
}}
</div>
<div class="col span-6">
<label class="acc-label">
{{t "clusterNew.googlegke.ipPolicyServicesSecondaryRangeName.label"}}
</label>
{{searchable-select
content=secondaryIpRangeContent
classNames="form-control"
value=config.ipPolicyServicesSecondaryRangeName
disabled=editing
}}
</div>
</div>
{{else}}
<div class="row">
<div class="col span-6">
<label class="acc-label">
{{t "clusterNew.googlegke.ipPolicyClusterSecondaryRangeName.label"}}
</label>
{{searchable-select
content=secondaryIpRangeContent
classNames="form-control"
value=config.ipPolicyClusterSecondaryRangeName
disabled=editing
}}
</div>
{{/if}}
<div class="col span-6">
<label class="acc-label">
{{t "clusterNew.googlegke.ipPolicyServicesSecondaryRangeName.label"}}
</label>
{{searchable-select
content=secondaryIpRangeContent
classNames="form-control"
value=config.ipPolicyServicesSecondaryRangeName
disabled=editing
}}
</div>
</div>
{{/if}}
{{/if}}
{{#advanced-section advanced=clusterAdvanced}}
<h4 class="mt-20 mb-10">
{{t "clusterNew.googlegke.header.privateCluster"}}
</h4>

View File

@ -40,7 +40,7 @@
@computedState={{not (eq selectedCloudProvider "none")}}
>
{{#input-or-display
editable=(not-eq mode "view")
editable=(or (and (eq mode "new") (or (not applyClusterTemplate) (and (eq mode "new") selectedCloudProviderOverrideAvailable))) clusterTemplateCreate)
value=selectedCloudProvider
}}
<div class="col span-6">
@ -134,7 +134,7 @@
</div>
{{/input-or-display}}
</CheckComputedOverride>
{{#unless (eq selectedCloudProvider "none")}}
{{#if (and (not-eq selectedCloudProvider "none") (eq mode "new"))}}
<div class="col span-6">
<BannerMessage
@color="bg-info mt-0 mb-0"
@ -142,7 +142,7 @@
@message={{t "cloudProvider.warning"}}
/>
</div>
{{/unless}}
{{/if}}
</div>
{{#if (eq selectedCloudProvider "azure")}}

View File

@ -16,9 +16,10 @@
@paramName="rancherKubernetesEngineConfig.network.plugin"
@clusterTemplateRevision={{clusterTemplateRevision.clusterConfig}}
@applyClusterTemplate={{applyClusterTemplate}}
as |override|
>
{{#input-or-display
editable=(eq mode "new")
editable=(or (and (eq mode "new") (or (not applyClusterTemplate) override.hasOverride)) clusterTemplateCreate)
value=config.network.plugin
}}
{{new-select

View File

@ -0,0 +1,34 @@
import Component from '@ember/component';
import layout from './template';
import { computed, get } from '@ember/object';
import StatefulPromise from 'shared/utils/stateful-promise';
export default Component.extend({
layout,
optionValues: computed.mapBy('asyncOptions.value', 'value'),
asyncOptions: computed('content', function() {
return StatefulPromise.wrap(get(this, 'options'), []);
}),
valueArray: computed('values', function() {
const values = get(this, 'values');
return Array.isArray(values)
? values
: [values];
}),
missingValues: computed('valueArray', 'optionValues', function() {
const optionValues = get(this, 'optionValues');
if (optionValues.length === 0) {
return [];
}
return get(this, 'valueArray').filter((value) => {
return optionValues.indexOf(value) === -1
});
}),
showMessaging: computed('values', 'missingValues.length', function() {
return get(this, 'values') && get(this, 'missingValues.length') > 0;
})
});

View File

@ -0,0 +1,10 @@
{{#if showMessaging}}
<div class="select-value-check text-small text-warning">
{{t "selectValueCheck.message" values=missingValues.length}}
<ul class="list-small">
{{#each missingValues as |missingValue|}}
<li>"{{missingValue}}"</li>
{{/each}}
</ul>
</div>
{{/if}}

View File

@ -1,4 +1,4 @@
import { schedule, cancel, later } from '@ember/runloop';
import { schedule, cancel, later, next } from '@ember/runloop';
import Mixin from '@ember/object/mixin';
import { get, set, setProperties } from '@ember/object';
import Ember from 'ember';
@ -121,17 +121,17 @@ export default Mixin.create({
// console.log(this.label, (forceRemove ? 'Remove' : 'Change'), type +':'+ event.data.id, projectId);
if ( get(this, 'updateProjectStore') && projectId && projectStore.hasType(type) ) {
if ( get(this, 'updateProjectStore') && projectId && checkStoreHasType(projectStore, type) ) {
// console.log(' Update project store', type, event.data.id, projectId);
updateStore(projectStore, event.data, forceRemove);
}
if ( get(this, 'updateClusterStore') && clusterStore.hasType(type) ) {
if ( get(this, 'updateClusterStore') && checkStoreHasType(clusterStore, type) ) {
// console.log(' Update cluster store', type, event.data.id);
updateStore(clusterStore, event.data, forceRemove);
}
if ( get(this, 'updateGlobalStore') && globalStore.hasType(type) ) {
if ( get(this, 'updateGlobalStore') && checkStoreHasType(globalStore, type)) {
// console.log(' Update global store', type, event.data.id);
updateStore(globalStore, event.data, forceRemove);
}
@ -143,6 +143,10 @@ export default Mixin.create({
Ember.endPropertyChanges();
// console.log(`Processed ${count} ${this.label} change events`);
function checkStoreHasType(store, type) {
return next(() => store.hasType(type));
}
function updateStore(store, data, forceRemove = false) {
// Update the state to removed before we remove it from store
if ( forceRemove ) {

View File

@ -0,0 +1 @@
export { default } from 'shared/components/select-value-check/component';

View File

@ -26,7 +26,7 @@
"devDependencies": {
"@ember/jquery": "^0.6.0",
"@ember/optional-features": "^0.7.0",
"@rancher/ember-api-store": "2.9.4",
"@rancher/ember-api-store": "2.9.6",
"ansi_up": "^2.0.2",
"async": "2.1.2",
"babel-eslint": "^9.0.0",
@ -65,6 +65,7 @@
"ember-drag-drop": "^0.4.7",
"ember-engines": "^0.8.2",
"ember-export-application-global": "^2.0.0",
"ember-fetch": "^6.5.1",
"ember-flatpickr": "^2.7.0",
"ember-href-to": "^2.0.1",
"ember-intl": "^4.2.0",

View File

@ -3620,12 +3620,13 @@ clusterNew:
label: Master IP range
placeholder: e.g. 10.42.0.0/28
useIpAliases:
label: Use Ip Aliases
label: Ip Aliases
ipPolicySubnetworkName:
label: Subnetwork Name
placeholder: Your Subnetwork Name
ipPolicyCreateSubnetwork:
label: Create Subnetwork
autoLabel: Auto Create Subnetwork
ipPolicyClusterSecondaryRangeName:
label: Cluster Secondary Range Name
placeholder: Your Cluster Secondary Range Name
@ -8313,6 +8314,9 @@ nodeDriver:
valuePlaceholder: "e.g. VM Network"
help: "Networks to attach VM to"
dataStore:
cluster:
tooltip: Use datastore cluster?
help: "Datastore cluster to create VM on"
label: Data Store
placeholder: "e.g. datastore_cluster_name/datastore_name"
help: "Datastore to create VM disk on"
@ -9823,3 +9827,10 @@ pipelineNotification:
recipients:
required: Recipient is required
asMessage: Send a message to
selectValueCheck:
message: |
{values, plural,
=1 {Please select a new value. The following is no longer valid:}
other {Please select new values. The following are no longer valid:}
}

View File

@ -1121,17 +1121,16 @@
resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b"
integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==
"@rancher/ember-api-store@2.9.4":
version "2.9.4"
resolved "https://registry.yarnpkg.com/@rancher/ember-api-store/-/ember-api-store-2.9.4.tgz#84920e719ce2c0306668db7fd031138c1fec8b72"
integrity sha512-Jef11/K9qGZyrSbufnlfDhY9WNfuo1th+azjRjDNwGv/7wrKiOxOquGmdKViWQXxjy8Hvm7RwsjKK5h2f85wpQ==
"@rancher/ember-api-store@2.9.6":
version "2.9.6"
resolved "https://registry.yarnpkg.com/@rancher/ember-api-store/-/ember-api-store-2.9.6.tgz#296195610a418c860dc98325e8aacaa53a159b62"
integrity sha512-SkJsDQiBPRzjjggJLT3mLPMJJBTKRTQbSjNdUoS7wjMWGqOzp+/XYtF8raov3cfYRja2D9bPV1HJo8OW2cF7dA==
dependencies:
babel-eslint "^10.0.1"
broccoli-file-creator "^2.1.1"
ember-auto-import "^1.2.19"
ember-cli-babel "^7.1.2"
ember-cookies "^0.4.0"
ember-fetch "^6.5.1"
eslint "^4.19.1"
node-fetch "^2.3.0"
set-cookie-parser "^2.2.1"