mirror of https://github.com/rancher/dashboard.git
420 lines
11 KiB
Vue
420 lines
11 KiB
Vue
<script>
|
|
import { CONFIG_MAP, SECRET, NAMESPACE } from '@shell/config/types';
|
|
import { get } from '@shell/utils/object';
|
|
import { _VIEW } from '@shell/config/query-params';
|
|
import LabeledSelect from '@shell/components/form/LabeledSelect';
|
|
import { LabeledInput } from '@components/Form/LabeledInput';
|
|
import { ref, watch } from 'vue';
|
|
|
|
export default {
|
|
emits: ['update:value', 'remove'],
|
|
|
|
components: {
|
|
LabeledSelect,
|
|
LabeledInput
|
|
},
|
|
|
|
props: {
|
|
mode: {
|
|
type: String,
|
|
default: 'create'
|
|
},
|
|
value: {
|
|
type: Object,
|
|
default: () => {
|
|
return { valueFrom: {} };
|
|
}
|
|
},
|
|
options: {
|
|
type: Array,
|
|
default: () => {
|
|
return [
|
|
{ value: 'simple', label: 'Key/Value Pair' },
|
|
{ value: 'resourceFieldRef', label: 'Resource' },
|
|
{ value: 'configMapKeyRef', label: 'ConfigMap Key' },
|
|
{ value: 'secretKeyRef', label: 'Secret Key' },
|
|
{ value: 'fieldRef', label: 'Pod Field' },
|
|
{ value: 'secretRef', label: 'Secret' },
|
|
{ value: 'configMapRef', label: 'ConfigMap' },
|
|
];
|
|
},
|
|
},
|
|
allConfigMaps: {
|
|
type: Array,
|
|
default: () => []
|
|
},
|
|
allSecrets: {
|
|
type: Array,
|
|
default: () => []
|
|
},
|
|
// filter resource options by namespace(s) selected in top nav
|
|
namespaced: {
|
|
type: Boolean,
|
|
default: true
|
|
},
|
|
loading: {
|
|
default: false,
|
|
type: Boolean
|
|
},
|
|
},
|
|
|
|
data() {
|
|
return {
|
|
secrets: this.allSecrets,
|
|
resourceKeyOpts: ['limits.cpu', 'limits.ephemeral-storage', 'limits.memory', 'requests.cpu', 'requests.ephemeral-storage', 'requests.memory'],
|
|
};
|
|
},
|
|
|
|
setup(props, { emit }) {
|
|
const type = ref(null);
|
|
|
|
if (props.value.secretRef) {
|
|
type.value = 'secretRef';
|
|
} else if (props.value.configMapRef) {
|
|
type.value = 'configMapRef';
|
|
} else if (props.value.value) {
|
|
type.value = 'simple';
|
|
} else if (props.value.valueFrom) {
|
|
type.value = Object.keys((props.value.valueFrom))[0] || props.options[0].value || 'simple';
|
|
}
|
|
|
|
const refName = ref('');
|
|
const name = ref('');
|
|
const fieldPath = ref('');
|
|
const referenced = ref(null);
|
|
const key = ref(null);
|
|
const valStr = ref('');
|
|
const keys = ref([]);
|
|
|
|
switch (type.value) {
|
|
case 'resourceFieldRef':
|
|
name.value = props.value.name;
|
|
refName.value = props.value.valueFrom?.[type.value]?.containerName;
|
|
key.value = props.value.valueFrom?.[type.value]?.resource || '';
|
|
break;
|
|
case 'configMapKeyRef':
|
|
name.value = props.value.name;
|
|
key.value = props.value.valueFrom?.[type.value]?.key || '';
|
|
refName.value = props.value.valueFrom?.[type.value]?.name;
|
|
referenced.value = props.allConfigMaps.filter((resource) => {
|
|
return resource.metadata.name === refName.value;
|
|
})[0];
|
|
if (referenced.value && referenced.value.data) {
|
|
keys.value.push(...Object.keys(referenced.value.data));
|
|
}
|
|
break;
|
|
case 'secretRef':
|
|
case 'configMapRef':
|
|
name.value = props.value.prefix;
|
|
refName.value = props.value[type.value]?.name;
|
|
break;
|
|
case 'secretKeyRef':
|
|
name.value = props.value.name;
|
|
key.value = props.value.valueFrom?.[type.value]?.key || '';
|
|
refName.value = props.value.valueFrom?.[type.value]?.name;
|
|
referenced.value = props.allSecrets.filter((resource) => {
|
|
return resource.metadata.name === refName.value;
|
|
})[0];
|
|
if (referenced.value && referenced.value.data) {
|
|
keys.value.push(...Object.keys(referenced.value.data));
|
|
}
|
|
break;
|
|
case 'fieldRef':
|
|
fieldPath.value = get(props.value.valueFrom, `${ type.value }.fieldPath`) || '';
|
|
name.value = props.value.name;
|
|
break;
|
|
default:
|
|
name.value = props.value.name;
|
|
valStr.value = props.value.value;
|
|
break;
|
|
}
|
|
|
|
referenced.value = refName.value;
|
|
|
|
const updateRow = () => {
|
|
if (!name.value?.length && !refName.value?.length) {
|
|
if (type.value !== 'fieldRef') {
|
|
emit('update:value', null);
|
|
|
|
return;
|
|
}
|
|
}
|
|
let out = { name: name.value || refName.value };
|
|
|
|
switch (type.value) {
|
|
case 'configMapKeyRef':
|
|
case 'secretKeyRef':
|
|
out.valueFrom = {
|
|
[type.value]: {
|
|
key: key.value, name: refName.value, optional: false
|
|
}
|
|
};
|
|
break;
|
|
case 'resourceFieldRef':
|
|
out.valueFrom = {
|
|
[type.value]: {
|
|
containerName: refName.value, divisor: 1, resource: key.value
|
|
}
|
|
};
|
|
break;
|
|
case 'fieldRef':
|
|
if (!fieldPath.value || !fieldPath.value.length) {
|
|
out = null; break;
|
|
}
|
|
out.valueFrom = { [type.value]: { apiVersion: 'v1', fieldPath: fieldPath.value } };
|
|
break;
|
|
case 'simple':
|
|
out.value = valStr.value;
|
|
break;
|
|
default:
|
|
delete out.name;
|
|
out.prefix = name.value;
|
|
out[type.value] = { name: refName.value, optional: false };
|
|
}
|
|
emit('update:value', out);
|
|
};
|
|
|
|
watch(type, () => {
|
|
referenced.value = null;
|
|
key.value = '';
|
|
refName.value = '';
|
|
keys.value = [];
|
|
key.value = '';
|
|
valStr.value = '';
|
|
fieldPath.value = '';
|
|
});
|
|
|
|
watch(referenced, (neu, old) => {
|
|
if (neu) {
|
|
if ((neu.type === SECRET || neu.type === CONFIG_MAP) && neu.data) {
|
|
keys.value = Object.keys(neu.data);
|
|
}
|
|
refName.value = neu?.metadata?.name;
|
|
}
|
|
updateRow();
|
|
});
|
|
|
|
return {
|
|
type,
|
|
refName,
|
|
referenced,
|
|
keys,
|
|
key,
|
|
fieldPath,
|
|
name,
|
|
valStr,
|
|
updateRow,
|
|
get,
|
|
};
|
|
},
|
|
|
|
computed: {
|
|
isView() {
|
|
return this.mode === _VIEW;
|
|
},
|
|
|
|
namespaces() {
|
|
if (this.namespaced) {
|
|
const map = this.$store.getters.namespaces();
|
|
|
|
return Object.keys(map).filter((key) => map[key]);
|
|
} else {
|
|
const inStore = this.$store.getters['currentStore'](NAMESPACE);
|
|
|
|
return this.$store.getters[`${ inStore }/all`](NAMESPACE);
|
|
}
|
|
},
|
|
|
|
sourceOptions() {
|
|
if (this.type === 'configMapKeyRef' || this.type === 'configMapRef') {
|
|
return this.allConfigMaps.filter((map) => this.namespaces.includes(map?.metadata?.namespace));
|
|
} else if (this.type === 'secretRef' || this.type === 'secretKeyRef') {
|
|
return this.allSecrets.filter((secret) => this.namespaces.includes(secret?.metadata?.namespace));
|
|
} else {
|
|
return [];
|
|
}
|
|
},
|
|
|
|
needsSource() {
|
|
return this.type !== 'simple' && this.type !== 'resourceFieldRef' && this.type !== 'fieldRef' && !!this.type;
|
|
},
|
|
|
|
sourceLabel() {
|
|
let out;
|
|
const { type } = this;
|
|
|
|
if (!type) {
|
|
return;
|
|
}
|
|
|
|
switch (type) {
|
|
case 'secretKeyRef':
|
|
case 'secretRef':
|
|
out = 'workload.container.command.fromResource.secret';
|
|
break;
|
|
case 'configMapKeyRef':
|
|
case 'configMapRef':
|
|
out = 'workload.container.command.fromResource.configMap';
|
|
break;
|
|
default:
|
|
out = 'workload.container.command.fromResource.source.label';
|
|
}
|
|
|
|
return this.t(out);
|
|
},
|
|
|
|
nameLabel() {
|
|
if (this.type === 'configMapRef' || this.type === 'secretRef') {
|
|
return this.t('workload.container.command.fromResource.prefix');
|
|
} else {
|
|
return this.t('workload.container.command.fromResource.name.label');
|
|
}
|
|
},
|
|
|
|
extraColumn() {
|
|
return ['resourceFieldRef', 'configMapKeyRef', 'secretKeyRef'].includes(this.type);
|
|
},
|
|
|
|
hideVariableName() {
|
|
return this.options?.find((opt) => opt.value === this.type)?.hideVariableName || false;
|
|
}
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div class="var-row">
|
|
<div class="type">
|
|
<LabeledSelect
|
|
v-model:value="type"
|
|
:mode="mode"
|
|
:multiple="false"
|
|
:options="options"
|
|
option-label="label"
|
|
:searchable="false"
|
|
:reduce="e=>e.value"
|
|
:label="t('workload.container.command.fromResource.type')"
|
|
@update:value="updateRow"
|
|
/>
|
|
</div>
|
|
|
|
<div
|
|
v-if="!hideVariableName"
|
|
class="name"
|
|
>
|
|
<LabeledInput
|
|
v-model:value="name"
|
|
:label="nameLabel"
|
|
:placeholder="t('workload.container.command.fromResource.name.placeholder')"
|
|
:mode="mode"
|
|
@update:value="updateRow"
|
|
/>
|
|
</div>
|
|
|
|
<div
|
|
v-if="type==='simple'"
|
|
class="single-value"
|
|
>
|
|
<LabeledInput
|
|
v-model:value="valStr"
|
|
:label="t('workload.container.command.fromResource.value.label')"
|
|
:placeholder="t('workload.container.command.fromResource.value.placeholder')"
|
|
:mode="mode"
|
|
@update:value="updateRow"
|
|
/>
|
|
</div>
|
|
|
|
<template v-else-if="needsSource">
|
|
<div :class="{'single-value': type === 'configMapRef' || type === 'secretRef'}">
|
|
<LabeledSelect
|
|
v-model:value="referenced"
|
|
:options="sourceOptions"
|
|
:multiple="false"
|
|
:get-option-label="opt=>get(opt, 'metadata.name') || opt"
|
|
:get-option-key="opt=>opt.id|| opt"
|
|
:mode="mode"
|
|
:label="sourceLabel"
|
|
:loading="loading"
|
|
/>
|
|
</div>
|
|
<div v-if="type!=='secretRef' && type!== 'configMapRef'">
|
|
<LabeledSelect
|
|
v-model:value="key"
|
|
:multiple="false"
|
|
:options="keys"
|
|
:mode="mode"
|
|
option-label="label"
|
|
:label="t('workload.container.command.fromResource.key.label')"
|
|
:loading="loading"
|
|
@update:value="updateRow"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<template v-else-if="type==='resourceFieldRef'">
|
|
<div>
|
|
<LabeledInput
|
|
v-model:value="refName"
|
|
:label="t('workload.container.command.fromResource.containerName')"
|
|
:placeholder="t('workload.container.command.fromResource.source.placeholder')"
|
|
:mode="mode"
|
|
@update:value="updateRow"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<LabeledSelect
|
|
v-model:value="key"
|
|
:label="t('workload.container.command.fromResource.key.label')"
|
|
:multiple="false"
|
|
:options="resourceKeyOpts"
|
|
:mode="mode"
|
|
:searchable="false"
|
|
:placeholder="t('workload.container.command.fromResource.key.placeholder', null, true)"
|
|
@update:value="updateRow"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<template v-else>
|
|
<div class="single-value">
|
|
<LabeledInput
|
|
v-model:value="fieldPath"
|
|
:placeholder="t('workload.container.command.fromResource.key.placeholder', null, true)"
|
|
:label="t('workload.container.command.fromResource.key.label')"
|
|
:mode="mode"
|
|
@update:value="updateRow"
|
|
/>
|
|
</div>
|
|
</template>
|
|
<div class="remove">
|
|
<button
|
|
v-if="!isView"
|
|
type="button"
|
|
class="btn role-link"
|
|
@click.stop="$emit('remove')"
|
|
>
|
|
{{ t('generic.remove') }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style lang='scss' scoped>
|
|
.var-row{
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr 1fr 1fr 100px;
|
|
grid-column-gap: 20px;
|
|
margin-bottom: 10px;
|
|
align-items: center;
|
|
|
|
.single-value {
|
|
grid-column: span 2;
|
|
}
|
|
|
|
.remove BUTTON {
|
|
padding: 0px;
|
|
}
|
|
}
|
|
|
|
</style>
|