Merge pull request #3566 from vincent99/master

[Master] Bugs
This commit is contained in:
Vincent Fiduccia 2021-07-29 13:20:17 -07:00 committed by GitHub
commit 2c9c9102bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 255 additions and 186 deletions

View File

@ -307,7 +307,7 @@ authConfig:
5: 'Upload the downloaded JSON file in the OAuth credentials box.'
3:
title: 'Create Service Account credentials'
introduction: 'Follow <a href="https://rancher.com/docs/rancher/v2.x/en/admin-settings/authentication/google/#creating-service-account-credentials" target="_blank" rel="noopener noreferrer nofollow">this</a> guide to:'
introduction: 'Follow <a href="{docsBase}/admin-settings/authentication/google/#creating-service-account-credentials" target="_blank" rel="noopener noreferrer nofollow">this</a> guide to:'
body:
1: Create a service account.
2: Generate a key for the service account.
@ -818,7 +818,7 @@ cis:
alertNeeded: |-
Alerting must be enabled within the CIS chart values.yaml.
This requires that the <a tabindex="0" href="{link}">{vendor} Monitoring and Alerting app</a> is installed
and the Receivers and Routes are <a target="_blank" rel='noopener noreferrer nofollow' href='https://rancher.com/docs/rancher/v2.x/en/monitoring-alerting/v2.5/configuration/#alertmanager-config'> configured to send out alerts.</a>
and the Receivers and Routes are <a target="_blank" rel='noopener noreferrer nofollow' href='{docsBase}/monitoring-alerting/v2.5/configuration/#alertmanager-config'> configured to send out alerts.</a>
alertOnComplete: Alert on scan completion
alertOnFailure: Alert on scan failure
benchmarkVersion: Benchmark Version
@ -2277,7 +2277,7 @@ monitoring:
keyFilePath:
label: Key File Path
placeholder: e.g. ./key-file.pfx
secretsBanner: The file paths below must be referenced in <pre class="inline-block m-0 p-0 vertical-middle">alertmanager.alertmanagerSpec.secrets</pre> when deploying the Monitoring chart. For more information see our <a href="https://rancher.com/docs/rancher/v2.5/en/monitoring-alerting/" target="_blank" rel="noopener noreferrer nofollow">documentation</a>.
secretsBanner: The file paths below must be referenced in <pre class="inline-block m-0 p-0 vertical-middle">alertmanager.alertmanagerSpec.secrets</pre> when deploying the Monitoring chart. For more information see our <a href="{docsBase}/monitoring-alerting/" target="_blank" rel="noopener noreferrer nofollow">documentation</a>.
route:
fields:
@ -2293,7 +2293,7 @@ monitoring:
stepTitle: Uninstall V1
stepSubtext: Uninstall Previous Monitoring
warning1: V1 Monitoring is currently deployed. This needs to be uninstalled before V2 monitoring can be installed.
warning2: <a target="blank" href="https://rancher.com/docs/rancher/v2.x/en/monitoring-alerting/v2.5/migrating/#migrating-from-monitoring-v1-to-monitoring-v2" target='_blank' rel='noopener nofollow'>Learn more</a> about the migration steps to V2 Monitoring.
warning2: <a target="blank" href="{docsBase}/monitoring-alerting/v2.5/migrating/#migrating-from-monitoring-v1-to-monitoring-v2" target='_blank' rel='noopener nofollow'>Learn more</a> about the migration steps to V2 Monitoring.
promptDescription: <div class="mt-20 mb-20">You are attempting to uninstall V1 Monitoring. Please ensure you have read the migration steps.</div>
success1: V1 monitoring successfully uninstalled.
success2: Press Next to continue
@ -3410,24 +3410,26 @@ servicesPage:
label: Service Type
setup:
currentPassword: Bootstrap Password
confirmPassword: Confirm New Password
defaultPasswordError: It looks like this is your first time visiting the Rancher UI; you will need to log in to the local <code>admin</code> account to continue to the setup process.<br><br>If the admin password wasn't preset with an environment variable during installation, one has been randomly generated for you and may be found in your install logs. Alternatively follow the instructions <a rel="noopener noreferrer nofollow" target="_blank" href="https://rancher.com/docs/rancher/v2.5/en/faq/technical/">here</a> to reset the admin password.
defaultPassword:
intro: It looks like this is your first time visiting {vendor}; if you pre-set your own bootstrap password, enter it here. Otherwise a random one has been generated for you.<br/><br/>
dockerPrefix: 'For a "docker run" installation:'
dockerCmd: 'docker logs <i>container-id</i> 2&gt;&amp;1 | grep "Bootstrap Password:"'
dockerPs: 'Find your container ID with <code>docker ps</code>, then run:'
dockerSuffix: ""
helmPrefix: 'For a Helm installation, run:'
helmCmd: "kubectl get secret --namespace cattle-system bootstrap-secret -o go-template='{{.data.bootstrapPassword|base64decode}}{{\"\\n\"}}'"
helmSuffix: ""
eula: I agree to the <a href="https://rancher.com/eula" target="_blank" rel="noopener noreferrer nofollow">terms and conditions</a> for using Rancher.
newPassword: New Password
newUserSetPassword: The first order of business is to set a strong password. We suggest using this random one generated just for you, but enter your own if you like.
serverUrl:
label: Server URL
skip: Skip
tip: What URL should be used for this Rancher installation? All the nodes in your clusters will need to be able to reach this. You can skip setting this for now, and update it later in General Settings>Advanced Settings.
tip: What URL should be used for this {vendor} installation? All the nodes in your clusters will need to be able to reach this.
setPassword: The first order of business is to set a strong password for the default <code>{username}</code> user. We suggest using this random one generated just for you, but enter your own if you like.
telemetry:
label: Allow collection of anonymous statistics to help us improve Rancher
tip: 'Rancher Labs would like to collect a bit of anonymized information
about the configuration of your installation to help make Rancher better.
Your data will not be shared with anyone else, and no information about
what specific resources or endpoints you are deploying is included.
Once enabled you can view exactly what data will be sent at <code>/v1-telemetry</code>.
<a href="https://rancher.com/docs/rancher/v2.x/en/faq/telemetry/" target="_blank" rel="noopener noreferrer nofollow">More Info</a>'
telemetry: Allow collection of <a href="{docsBase}/faq/telemetry/" target="_blank" rel="noopener noreferrer nofollow">anonymous statistics</a> to help us improve {vendor}.
useManual: Set a specific password to use
useRandom: Use a randomly generated password
welcome: Welcome to {vendor}!
@ -4997,13 +4999,13 @@ embedding:
v1ClusterTools:
monitoring:
label: Monitoring (Legacy)
description: 'Legacy V1 monitoring. V1 Monitoring is deprecated since Rancher 2.5.0. <a target="blank" href="https://rancher.com/docs/rancher/v2.x/en/monitoring-alerting/v2.5/migrating/#migrating-from-monitoring-v1-to-monitoring-v2">Learn more</a> about the migration steps to V2 Monitoring.'
description: 'Legacy V1 monitoring. V1 Monitoring is deprecated since Rancher 2.5.0. <a target="blank" href="{docsBase}/monitoring-alerting/v2.5/migrating/#migrating-from-monitoring-v1-to-monitoring-v2">Learn more</a> about the migration steps to V2 Monitoring.'
logging:
label: Logging (Legacy)
description: 'Legacy V1 logging. V1 Logging is deprecated since Rancher 2.5.0. <a target="blank" href="https://rancher.com/docs/rancher/v2.x/en/logging/v2.5/migrating/">Learn more</a> about migrating to V2 Logging.'
description: 'Legacy V1 logging. V1 Logging is deprecated since Rancher 2.5.0. <a target="blank" href="{docsBase}/logging/v2.5/migrating/">Learn more</a> about migrating to V2 Logging.'
istio:
label: Istio (Legacy)
description: 'Legacy V1 Istio. Istio v1.5 has been deprecated since Rancher 2.5.0. <a target="blank" href="https://rancher.com/docs/rancher/v2.5/en/istio/#migrate-from-previous-istio-version">Learn more</a> about migrating to the latest version.'
description: 'Legacy V1 Istio. Istio v1.5 has been deprecated since Rancher 2.5.0. <a target="blank" href="{docsBase}/istio/#migrate-from-previous-istio-version">Learn more</a> about migrating to the latest version.'
legacy:
alerts: Alerts

View File

@ -9,6 +9,10 @@ export default {
mixins: [CreateEditView],
data() {
if ( !this.value.decodedData.environment ) {
this.value.setData('environment', 'AzurePublicCloud');
}
return { azureEnvironments };
},
@ -22,9 +26,6 @@ export default {
'value.decodedData.subscriptionId'(neu) {
this.$emit('validationChanged', !!neu);
},
'value.decodedData.tenantId'(neu) {
this.$emit('validationChanged', !!neu);
},
'value.decodedData.environment'(neu) {
this.$emit('validationChanged', !!neu);
},
@ -36,7 +37,6 @@ export default {
clientId,
clientSecret,
subscriptionId,
tenantId,
} = this.value.decodedData;
try {
@ -47,7 +47,6 @@ export default {
clientId,
clientSecret,
subscriptionId,
tenantId,
},
});
@ -62,46 +61,6 @@ export default {
<template>
<section>
<div class="row mb-10">
<div class="col span-6">
<LabeledInput
:value="value.decodedData.tenantId"
label-key="cluster.credential.azure.tenantId.label"
type="text"
:mode="mode"
@input="value.setData('tenantId', $event)"
/>
</div>
<div class="col span-6">
<LabeledInput
:value="value.decodedData.subscriptionId"
label-key="cluster.credential.azure.subscriptionId.label"
type="text"
:mode="mode"
@input="value.setData('subscriptionId', $event)"
/>
</div>
</div>
<div class="row mb-10">
<div class="col span-6">
<LabeledInput
:value="value.decodedData.clientId"
label-key="cluster.credential.azure.clientId.label"
type="text"
:mode="mode"
@input="value.setData('clientId', $event)"
/>
</div>
<div class="col span-6">
<LabeledInput
:value="value.decodedData.clientSecret"
label-key="cluster.credential.azure.clientSecret.label"
type="password"
:mode="mode"
@input="value.setData('clientSecret', $event)"
/>
</div>
</div>
<div class="row mb-10">
<div class="col span-6">
<LabeledSelect
@ -116,6 +75,38 @@ export default {
@input="value.setData('environment', $event)"
/>
</div>
<div class="col span-6">
<LabeledInput
:value="value.decodedData.subscriptionId"
label-key="cluster.credential.azure.subscriptionId.label"
type="text"
:mode="mode"
:required="true"
@input="value.setData('subscriptionId', $event)"
/>
</div>
</div>
<div class="row mb-10">
<div class="col span-6">
<LabeledInput
:value="value.decodedData.clientId"
label-key="cluster.credential.azure.clientId.label"
type="text"
:mode="mode"
:required="true"
@input="value.setData('clientId', $event)"
/>
</div>
<div class="col span-6">
<LabeledInput
:value="value.decodedData.clientSecret"
label-key="cluster.credential.azure.clientSecret.label"
type="password"
:mode="mode"
:required="true"
@input="value.setData('clientSecret', $event)"
/>
</div>
</div>
</section>
</template>

View File

@ -1,4 +1,16 @@
<script>
import { isArray } from '@/utils/array';
function flatten(node) {
if ( isArray(node) ) {
return node.map(flatten).join(' ');
} else if ( node.children ) {
return node.children.map(flatten).join(' ');
} else if ( node.text ) {
return node.text;
}
}
export default {
data() {
return { copied: false };
@ -9,7 +21,9 @@ export default {
$event.stopPropagation();
$event.preventDefault();
this.$copyText(this.$slots.default[0].text.trim()).then(() => {
const content = flatten(this.$slots.default).trim();
this.$copyText(content).then(() => {
this.copied = true;
setTimeout(() => {

View File

@ -72,28 +72,39 @@ export default {
methods: {
clicked(event) {
if (!this.isDisabled) {
const click = $.Event('click');
if ( event.target.tagName === 'A' && event.target.href ) {
// Ignore links inside the checkbox label so you can click them
return true;
}
click.shiftKey = event.shiftKey;
click.altKey = event.altKey;
click.ctrlKey = event.ctrlKey;
click.metaKey = event.metaKey;
event.stopPropagation();
event.preventDefault();
// Flip the value
if (this.isMulti()) {
if (this.isChecked) {
removeObject(this.value, this.valueWhenTrue);
} else {
addObject(this.value, this.valueWhenTrue);
}
this.$emit('input', this.value);
if (this.isDisabled) {
return;
}
const click = $.Event('click');
click.shiftKey = event.shiftKey;
click.altKey = event.altKey;
click.ctrlKey = event.ctrlKey;
click.metaKey = event.metaKey;
// Flip the value
if (this.isMulti()) {
if (this.isChecked) {
removeObject(this.value, this.valueWhenTrue);
} else {
this.$emit('input', !this.value);
$(this.$el).trigger(click);
addObject(this.value, this.valueWhenTrue);
}
this.$emit('input', this.value);
} else {
this.$emit('input', !this.value);
$(this.$el).trigger(click);
}
},
isMulti() {
return Array.isArray(this.value);
}
@ -108,7 +119,7 @@ export default {
:class="{ 'disabled': isDisabled}"
@keydown.enter.prevent="clicked($event)"
@keydown.space.prevent="clicked($event)"
@click.stop.prevent="clicked($event)"
@click="clicked($event)"
>
<input
v-model="value"

View File

@ -123,6 +123,10 @@ export default {
type: Boolean,
default: true,
},
valueTrim: {
type: Boolean,
default: true,
},
valueBase64: {
type: Boolean,
default: false,
@ -373,7 +377,11 @@ export default {
if (value && typeOf(value) === 'object') {
out[key] = JSON.parse(JSON.stringify(value));
} else {
value = (value || '').trim();
value = value || '';
if ( this.valueTrim ) {
value = value.trim();
}
if ( value && this.valueBase64 ) {
value = base64Encode(value);

View File

@ -99,7 +99,7 @@ export const fetchOrCreateSetting = async(store, id, val, save = true) => {
});
if ( save ) {
setting.save({ url });
await setting.save({ url });
}
}
@ -111,5 +111,7 @@ export const setSetting = async(store, id, val) => {
setting.value = val;
return setting.save();
await setting.save();
return setting;
};

View File

@ -53,6 +53,7 @@ export default {
:mode="mode"
:initial-empty-row="true"
:value-base64="true"
:value-trim="false"
:value-concealed="isView && hideSensitiveData"
:file-modifier="fileModifier"
read-icon=""

View File

@ -345,6 +345,16 @@ export default {
this.$set(this.value, 'tags', ary.join(','));
},
test() {
const errors = [];
if (!this.selectedNetwork) {
errors.push(this.t('validation.required', { key: 'VPC/Subnet' }, true));
}
return { errors };
},
},
};
</script>

View File

@ -6,7 +6,7 @@ import { createCssVars } from '@/utils/color';
export default {
async fetch() {
this.globalSettings = await this.$store.dispatch('management/findAll', { type: MANAGEMENT.SETTING });
this.globalSettings = await this.$store.dispatch('management/findAll', { type: MANAGEMENT.SETTING, opt: { url: `/v1/${ MANAGEMENT.SETTING }` } });
},
data() {

View File

@ -30,6 +30,10 @@ export default {
return out;
},
canClone() {
return false;
},
openSsh() {
return () => {
this.$dispatch('wm/open', {

View File

@ -383,6 +383,10 @@ export default {
return true;
},
canClone() {
return false;
},
// You need to preload CAPI.MACHINEs to use this
provisionedMachine() {
const namespace = this.metadata?.annotations?.[CAPI_ANNOTATIONS.CLUSTER_NAMESPACE];

View File

@ -85,6 +85,9 @@ export default {
id: this.namespace
}
};
}
},
canClone() {
return false;
},
};

View File

@ -61,7 +61,7 @@ export default {
label: 'Download KubeConfig',
icon: 'icon icon-download',
bulkable: true,
enabled: this.$rootGetters['isRancher'],
enabled: this.$rootGetters['isRancher'] && this.mgmt?.isReady,
});
insertAt(out, idx++, {

View File

@ -4,6 +4,8 @@ import { USERNAME } from '@/config/cookies';
import LabeledInput from '@/components/form/LabeledInput';
import AsyncButton from '@/components/AsyncButton';
import BrandImage from '@/components/BrandImage';
import InfoBox from '@/components/InfoBox';
import CopyCode from '@/components/CopyCode';
import Banner from '@/components/Banner';
import { LOCAL, LOGGED_OUT, TIMED_OUT, _FLAGGED } from '@/config/query-params';
import Checkbox from '@/components/form/Checkbox';
@ -15,13 +17,13 @@ import { _ALL_IF_AUTHED } from '@/plugins/steve/actions';
import { MANAGEMENT, NORMAN } from '@/config/types';
import { SETTING } from '@/config/settings';
import { LOGIN_ERRORS } from '@/store/auth';
import { getVendor, getProduct, setVendor } from '../../config/private-label';
import { getVendor, getProduct, setVendor } from '@/config/private-label';
export default {
name: 'Login',
layout: 'unauthenticated',
components: {
LabeledInput, AsyncButton, Checkbox, BrandImage, Banner
LabeledInput, AsyncButton, Checkbox, BrandImage, Banner, InfoBox, CopyCode
},
async asyncData({ route, redirect, store }) {
@ -229,8 +231,8 @@ export default {
<template>
<main class="login">
<div class="row mb-20">
<div class="col span-6">
<div class="row gutless mb-20">
<div class="col span-6 p-20">
<p class="text-center">
{{ t('login.howdy') }}
</p>
@ -249,9 +251,31 @@ export default {
</h4>
</div>
<div v-if="firstLogin" class="first-login-message">
<Banner color="info">
<t k="setup.defaultPasswordError" :raw="true" />
</Banner>
<InfoBox color="info">
<t k="setup.defaultPassword.intro" :raw="true" />
<div><t k="setup.defaultPassword.dockerPrefix" :raw="true" /></div>
<ul>
<li>
<t k="setup.defaultPassword.dockerPs" :raw="true" />
</li>
<li>
<CopyCode>
<t k="setup.defaultPassword.dockerCmd" :raw="true" />
</CopyCode>
</li>
</ul>
<div><t k="setup.defaultPassword.dockerSuffix" :raw="true" /></div>
<br />
<div><t k="setup.defaultPassword.helmPrefix" :raw="true" /></div>
<br />
<CopyCode>
<t k="setup.defaultPassword.helmCmd" :raw="true" />
</CopyCode>
<br />
<div><t k="setup.defaultPassword.helmSuffix" :raw="true" /></div>
</InfoBox>
</div>
<div v-if="(!hasLocal || (hasLocal && !showLocal)) && providers.length" class="mt-30">

View File

@ -23,7 +23,9 @@ const calcIsFirstLogin = (store) => {
const calcMustChangePassword = async(store) => {
await store.dispatch('auth/getUser');
return store.getters['auth/v3User']?.mustChangePassword;
const out = store.getters['auth/v3User']?.mustChangePassword;
return out;
};
export default {
@ -40,8 +42,8 @@ export default {
} catch (e) {
}
const isFirstLogin = calcIsFirstLogin(store);
const mustChangePassword = calcMustChangePassword(store);
const isFirstLogin = await calcIsFirstLogin(store);
const mustChangePassword = await calcMustChangePassword(store);
if (isFirstLogin) {
// Always show setup if this is the first log in
@ -81,7 +83,7 @@ export default {
const principals = await store.dispatch('rancher/findAll', { type: NORMAN.PRINCIPAL, opt: { url: '/v3/principals' } });
const me = findBy(principals, 'me', true);
const current = route.query[SETUP] || store.getters['auth/initialPass'] || 'admin';
const current = route.query[SETUP] || store.getters['auth/initialPass'];
const v3User = store.getters['auth/v3User'] ?? {};
const mcmFeature = await store.dispatch('management/find', {
@ -100,8 +102,8 @@ export default {
serverUrl = window.location.origin;
}
const isFirstLogin = calcIsFirstLogin(store);
const mustChangePassword = calcMustChangePassword(store);
const isFirstLogin = await calcIsFirstLogin(store);
const mustChangePassword = await calcMustChangePassword(store);
return {
vendor: getVendor(),
@ -111,8 +113,8 @@ export default {
useRandom: true,
haveCurrent: !!current,
username: me?.loginName || 'admin',
mustSetup: isFirstLogin,
mustChangePassword: isFirstLogin || mustChangePassword,
isFirstLogin,
mustChangePassword,
current,
password: randomStr(),
confirm: '',
@ -132,24 +134,24 @@ export default {
},
computed: {
passwordSubmitDisabled() {
if (!this.eula && this.mustSetup) {
return true;
}
if ( this.useRandom ) {
saveEnabled() {
if ( !this.eula ) {
return false;
}
if ( !this.password || this.password !== this.confirm ) {
return true;
if ( this.mustChangePassword ) {
if ( !this.current ) {
return false;
}
if ( !this.useRandom ) {
if ( !this.password || this.password !== this.confirm ) {
return false;
}
}
}
if ( !this.current ) {
return true;
}
return false;
return true;
},
me() {
@ -174,64 +176,56 @@ export default {
},
mounted() {
this.$refs.password.focus();
this.$refs.password.select();
const el = this.$refs.password;
if ( el ) {
el.focus();
el.select();
}
},
methods: {
async finishPassword(buttonCb) {
async save(buttonCb) {
const promises = [];
try {
if (this.mustSetup) {
await this.$store.dispatch('loadManagement');
await this.$store.dispatch('loadManagement');
await Promise.all([
setSetting(this.$store, SETTING.EULA_AGREED, (new Date()).toISOString() ),
setSetting(this.$store, SETTING.TELEMETRY, this.telemetry ? 'in' : 'out'),
setSetting(this.$store, SETTING.FIRST_LOGIN, 'false'),
]);
if ( this.mustChangePassword ) {
await this.$store.dispatch('rancher/request', {
url: '/v3/users?action=changepassword',
method: 'post',
data: {
currentPassword: this.current,
newPassword: this.password
},
});
} else {
promises.push(setSetting(this.$store, SETTING.FIRST_LOGIN, 'false'));
}
await this.$store.dispatch('rancher/request', {
url: '/v3/users?action=changepassword',
method: 'post',
data: {
currentPassword: this.current,
newPassword: this.password
},
});
const user = this.v3User;
user.mustChangePassword = false;
this.$store.dispatch('auth/gotUser', user);
if (!this.mustSetup && this.mustChangePassword) {
buttonCb(true);
this.done();
} else {
if (this.mcmEnabled) {
this.step = 2;
} else {
this.done();
}
buttonCb(true);
promises.push( setSetting(this.$store, SETTING.EULA_AGREED, (new Date()).toISOString()) );
promises.push( setSetting(this.$store, SETTING.TELEMETRY, this.telemetry ? 'in' : 'out') );
if ( this.mcmEnabled && this.serverUrl ) {
promises.push( setSetting(this.$store, SETTING.SERVER_URL, this.serverUrl) );
}
await Promise.all(promises);
buttonCb(true);
this.done();
} catch (err) {
buttonCb(false);
this.errors = exceptionToErrorsArray(err);
}
},
async setServerUrl(buttonCb) {
try {
await setSetting(this.$store, SETTING.SERVER_URL, this.serverUrl);
buttonCb(true);
this.done();
} catch {
buttonCb(false);
}
},
done() {
this.$router.replace('/');
},
@ -240,7 +234,7 @@ export default {
</script>
<template>
<div class="setup">
<form class="setup">
<div class="row">
<div class="col span-6 form-col">
<div>
@ -251,12 +245,21 @@ export default {
{{ t('setup.welcome', {product}) }}
</h1>
<template v-if="step===1">
<template v-if="mustChangePassword">
<p
class="text-center mb-40 mt-20 setup-title"
v-html="t(mustSetup ? 'setup.setPassword' : 'setup.newUserSetPassword', { username }, true)"
class="text-center mb-20 mt-20 setup-title"
v-html="t(isFirstLogin ? 'setup.setPassword' : 'setup.newUserSetPassword', { username }, true)"
></p>
<LabeledInput
v-if="!haveCurrent"
v-model.trim="current"
autocomplete="current-password"
type="password"
label-key="setup.currentPassword"
class="mb-20"
/>
<!-- For password managers... -->
<input type="hidden" name="username" autocomplete="username" :value="username" />
<div class="mb-20">
@ -284,38 +287,29 @@ export default {
type="password"
label-key="setup.confirmPassword"
/>
<div v-if="mustSetup">
<div class="checkbox mt-40">
<Checkbox v-model="telemetry" :label="t('setup.telemetry.label')" type="checkbox" />
<i v-tooltip="{content:t('setup.telemetry.tip', {}, true), delay: {hide:500}, autoHide: false}" class="icon icon-info" />
</div>
<div class="checkbox pt-10 eula">
<Checkbox v-model="eula" type="checkbox" />
<span v-html="t('setup.eula', {}, true)"></span>
</div>
</div>
<div class="text-center mt-20">
<AsyncButton key="passwordSubmit" type="submit" mode="continue" :disabled="passwordSubmitDisabled" @click="finishPassword" />
</div>
</template>
<template v-else>
<template v-if="mcmEnabled">
<hr v-if="mustChangePassword" class="mt-20 mb-20" />
<p>
<t k="setup.serverUrl.tip" :raw="true" />
</p>
<div class="mt-20">
<LabeledInput v-model="serverUrl" :label="t('setup.serverUrl.label')" />
</div>
<div class="text-center mt-20">
<button type="button" class="btn role-link" @click="done">
{{ t('setup.serverUrl.skip') }}
</button>
<AsyncButton type="submit" mode="continue" @click="setServerUrl" />
</div>
</template>
<div class="checkbox mt-40">
<Checkbox v-model="telemetry" label-key="setup.telemetry" />
</div>
<div class="checkbox pt-10 eula">
<Checkbox v-model="eula" label-key="setup.eula" />
</div>
<div class="text-center mt-20">
<AsyncButton key="passwordSubmit" type="submit" mode="continue" :disabled="!saveEnabled" @click="save" />
</div>
<div class="setup-errors mt-20">
<h4 v-for="err in errors" :key="err" class="text-error text-center">
{{ err }}
@ -326,7 +320,7 @@ export default {
<div class="col span-6 landscape" />
</div>
</div>
</form>
</template>
<style lang="scss" scoped>

View File

@ -122,7 +122,7 @@ export default {
try {
ns = await this.$store.dispatch('cluster/find', { type: NAMESPACE, id: this.forceNamespace });
const project = ns.metadata.annotations[PROJECT];
const project = ns.metadata.annotations?.[PROJECT];
if (project) {
this.project = project.replace(':', '/');
@ -492,7 +492,7 @@ export default {
if (neu) {
const ns = this.$store.getters['cluster/byId'](NAMESPACE, this.value.metadata.namespace);
const project = ns?.metadata.annotations[PROJECT];
const project = ns?.metadata.annotations?.[PROJECT];
if (project) {
this.project = project.replace(':', '/');

View File

@ -70,7 +70,7 @@ export const getters = {
msg = get(state.translations[state.default], key);
}
if ( !msg ) {
if ( msg === undefined ) {
return undefined;
}
@ -94,8 +94,9 @@ export const getters = {
} else if ( formatter && formatter.format ) {
// Inject things like appName so they're always available in any translation
const moreArgs = {
vendor: getVendor(),
appName: getProduct(),
vendor: getVendor(),
appName: getProduct(),
docsBase: 'https://rancher.com/docs/rancher/v2.6/en',
...args
};

View File

@ -95,7 +95,7 @@ export const HIDE_HOME_PAGE_CARDS = create('home-page-cards', {}, { parseJSON }
export const _RKE1 = 'rke1';
export const _RKE2 = 'rke2';
export const PROVISIONER = create('provisioner', _RKE2, { options: [_RKE1, _RKE2] });
export const PROVISIONER = create('provisioner', _RKE1, { options: [_RKE1, _RKE2] });
// Promo for Cluster Tools feature on Cluster Dashboard page
export const CLUSTER_TOOLS_TIP = create('hide-cluster-tools-tip', false, { parseJSON });