dashboard/shell/components/fleet/FleetValuesFrom.vue

296 lines
6.8 KiB
Vue

<script lang="ts">
import { isEmpty } from 'lodash';
import { checkSchemasForFindAllHash } from '@shell/utils/auth';
import { CONFIG_MAP, SECRET } from '@shell/config/types';
import { PropType } from 'vue';
import { _EDIT, _VIEW } from '@shell/config/query-params';
import { RcButton } from '@components/RcButton';
import ValueFromResource from '@shell/components/form/ValueFromResource.vue';
type KeyRefName = 'configMapKeyRef' | 'secretKeyRef';
interface KeyRef {
key: string,
name: string,
namespace?: string,
}
interface ValueFrom {
configMapKeyRef?: KeyRef,
secretKeyRef?: KeyRef,
}
interface ValuesFrom {
id: number,
valueFrom: ValueFrom
}
interface DataType {
allSecrets: object[] | null,
allConfigMaps: object[] | null,
valuesFrom: ValuesFrom[],
id: number,
}
export default {
name: 'FleetValuesFrom',
emits: ['update:value'],
components: {
RcButton,
ValueFromResource
},
props: {
value: {
type: Array as PropType<ValueFrom[]>,
default: () => []
},
namespace: {
type: String,
default: ''
},
mode: {
type: String,
default: _EDIT
},
},
async fetch() {
const hash = await checkSchemasForFindAllHash({
allSecrets: {
inStoreType: 'management',
type: SECRET
},
allConfigMaps: {
inStoreType: 'management',
type: CONFIG_MAP
}
}, this.$store) as { allSecrets: object[], allConfigMaps: object[] };
this.allSecrets = hash.allSecrets || [];
this.allConfigMaps = hash.allConfigMaps || [];
},
data(): DataType {
return {
allSecrets: null,
allConfigMaps: null,
valuesFrom: [],
id: 0,
};
},
mounted() {
this.valuesFrom = this.fromValuesFrom(this.value);
},
watch: {
namespace() {
this.valuesFrom = [];
this.update();
},
},
computed: {
valueFromOptions() {
return [
{
value: 'configMapKeyRef', label: this.t('fleet.helmOp.values.valuesFrom.options.configMapKeyRef'), hideVariableName: true
},
{
value: 'secretKeyRef', label: this.t('fleet.helmOp.values.valuesFrom.options.secretKeyRef'), hideVariableName: true
},
];
},
isView(): boolean {
return this.mode === _VIEW;
}
},
methods: {
addValueFrom() {
this.valuesFrom.push({
id: this.id++,
valueFrom: {}
});
this.update();
(this.$refs['add-button'] as { $el: HTMLElement })?.$el?.blur();
},
updateValueFrom(id: number, value: ValuesFrom) {
for (let index = 0; index < this.valuesFrom.length; index++) {
if (this.valuesFrom[index].id === id) {
const oldKeyRefName = Object.keys(this.valuesFrom[index]?.valueFrom || {})[0] as KeyRefName;
const newKeyRefName = Object.keys(value?.valueFrom || {})[0] as KeyRefName;
const oldKey = this.valuesFrom[index]?.valueFrom?.[oldKeyRefName]?.name;
const newKey = value?.valueFrom?.[newKeyRefName]?.name;
if (oldKeyRefName && newKeyRefName && oldKeyRefName !== newKeyRefName) {
this.valuesFrom[index].valueFrom = { [newKeyRefName]: {} };
} else if (oldKey && newKey && oldKey !== newKey) {
this.valuesFrom[index].valueFrom = {
[newKeyRefName]: {
...(value?.valueFrom?.[newKeyRefName] || {}),
key: ''
},
};
} else {
this.valuesFrom[index].valueFrom = value?.valueFrom;
}
break;
}
}
this.update();
},
removeValueFrom(id: number) {
this.valuesFrom = this.valuesFrom.filter((el) => el.id !== id);
this.update();
},
update() {
const value = this.toValuesFrom(this.valuesFrom, this.namespace);
this.$emit('update:value', value);
},
fromValuesFrom(data: ValueFrom[]): ValuesFrom[] {
return (data || [])
.map((elem) => {
const out = { id: this.id++ } as ValuesFrom;
const cm = elem?.configMapKeyRef;
if (cm) {
out.valueFrom = {
configMapKeyRef: {
key: cm.key || '',
name: cm.name || '',
}
};
}
const sc = elem?.secretKeyRef;
if (sc) {
out.valueFrom = {
secretKeyRef: {
key: sc.key || '',
name: sc.name || '',
}
};
}
return out;
})
.filter((el) => !isEmpty(el || {}));
},
toValuesFrom(data: { valueFrom: ValueFrom }[], namespace: string): ValueFrom[] | undefined {
const res = (data || [])
.map((elem) => {
const cm = elem?.valueFrom?.configMapKeyRef;
const sc = elem?.valueFrom?.secretKeyRef;
const out = {} as ValueFrom;
if (cm?.name) {
out.configMapKeyRef = {
key: cm.key,
name: cm.name,
namespace
};
}
if (sc?.name) {
out.secretKeyRef = {
key: sc.key,
name: sc.name,
namespace
};
}
return out;
})
.filter((el) => !isEmpty(el || {}));
return res.length ? res : undefined;
}
}
};
</script>
<template>
<div
v-if="!allConfigMaps || !allSecrets"
data-testid="fleet-values-from-loading"
>
<i
class="icon icon-lg icon-spinner icon-spin"
/>
<label class="text-label ml-10">
{{ t('fleet.helmOp.values.valuesFrom.loading') }}
</label>
</div>
<div
v-else
class="values-from-container"
data-testid="fleet-values-from-list"
>
<h2
v-t="'fleet.helmOp.values.valuesFrom.selectLabel'"
class="m-0"
/>
<div
v-for="row in valuesFrom"
:key="row.id + '-' + row?.valueFrom?.configMapKeyRef?.key + '-' + row?.valueFrom?.secretKeyRef?.key"
class="mmt-4"
>
<ValueFromResource
:data-testid="`fleet-values-from-item-${ row.id }`"
:value="row"
:options="valueFromOptions"
:all-secrets="allSecrets"
:all-config-maps="allConfigMaps"
:namespaced="true"
:mode="mode"
:show-variable-name="true"
@remove="removeValueFrom(row.id)"
@update:value="updateValueFrom(row.id, $event)"
/>
</div>
<RcButton
v-if="!isView"
ref="add-button"
small
secondary
class="mmt-6"
data-testid="fleet-values-from-add"
@click="addValueFrom"
>
<i class="icon icon-add" />
{{ t('workload.container.command.addEnvVar') }}
</RcButton>
</div>
</template>
<style lang="scss" scoped>
.var-row {
margin-bottom: 0;
}
</style>