dashboard/shell/edit/workload/storage/ContainerMountPaths.vue

233 lines
5.9 KiB
Vue

<script>
import { clone } from '@shell/utils/object';
import { _VIEW } from '@shell/config/query-params';
import { randomStr } from '@shell/utils/string';
import Mount from '@shell/edit/workload/storage/Mount';
import ButtonDropdown from '@shell/components/ButtonDropdown';
import ArrayListGrouped from '@shell/components/form/ArrayListGrouped';
export default {
name: 'ContainerMountPaths',
components: {
ArrayListGrouped, ButtonDropdown, Mount
},
props: {
mode: {
type: String,
default: 'create',
},
// pod spec
value: {
type: Object,
default: () => {
return {};
},
},
container: {
type: Object,
default: () => {
return {};
},
},
},
data() {
this.initializeStorage();
return {
containerVolumes: [],
storageVolumes: this.getStorageVolumes(),
selectedContainerVolumes: this.getSelectedContainerVolumes()
};
},
computed: {
isView() {
return this.mode === _VIEW;
},
availableVolumeOptions() {
const containerVolumes = this.container.volumeMounts.map((item) => item.name);
return this.value.volumes.filter((vol) => !containerVolumes.includes(vol.name)).map((item) => {
return {
label: `${ item.name } (${ this.headerFor(item) })`,
action: this.selectVolume,
value: item.name
};
});
},
},
watch: {
value(neu, old) {
this.selectedVolumes = this.getSelectedContainerVolumes();
},
storageVolumes(neu, old) {
// removeObjects(this.value.volumes, old);
// addObjects(this.value.volumes, neu);
const names = neu.reduce((all, each) => {
all.push(each.name);
return all;
}, []);
this.container.volumeMounts = this.container.volumeMounts.filter((mount) => names.includes(mount.name));
},
selectedContainerVolumes(neu, old) {
// removeObjects(this.value.volumes, old);
// addObjects(this.value.volumes, neu);
const names = neu.map((item) => item.name);
this.container.volumeMounts = this.container.volumeMounts.filter((mount) => names.includes(mount.name));
}
},
methods: {
/**
* Initialize missing values for the container
*/
initializeStorage() {
if (!this.container.volumeMounts) {
this.$set(this.container, 'volumeMounts', []);
}
if (!this.value.volumes) {
this.$set(this.value, 'volumes', []);
}
},
/**
* Get existing paired storage volumes
*/
getStorageVolumes() {
// Extract volume mounts to map storage volumes
const { volumeMounts = [] } = this.container;
const names = volumeMounts.map(({ name }) => name);
// Extract storage volumes to allow mutation, if matches mount map
return clone(this.value.volumes.filter((volume) => names.includes(volume.name)));
},
getSelectedContainerVolumes() {
// Extract volume mounts to map storage volumes
const { volumeMounts = [] } = this.container;
const names = volumeMounts.map(({ name }) => name);
// Extract storage volumes to allow mutation, if matches mount map
return clone(this.value.volumes.filter((volume) => names.includes(volume.name)));
},
/**
* Remove all mounts for given storage volume
*/
removeVolume(volume) {
const removeName = volume.row.value.name;
this.selectedContainerVolumes = this.selectedContainerVolumes.filter(({ name }) => name !== removeName);
},
selectVolume(event) {
const selectedVolume = this.value.volumes.find((vol) => vol.name === event.value);
this.selectedContainerVolumes.push(selectedVolume);
const { name } = selectedVolume;
this.container.volumeMounts.push(name);
},
addVolume(type) {
const name = `vol-${ randomStr(5).toLowerCase() }`;
if (type === 'createPVC') {
this.storageVolumes.push({
_type: 'createPVC',
persistentVolumeClaim: {},
name,
});
} else if (type === 'csi') {
this.storageVolumes.push({
_type: type,
csi: { volumeAttributes: {} },
name,
});
} else {
this.storageVolumes.push({
_type: type,
[type]: {},
name,
});
}
this.container.volumeMounts.push({ name });
},
headerFor(value) {
const type = Object.keys(value).filter(
(key) => typeof value[key] === 'object'
)[0];
if (
this.$store.getters['i18n/exists'](`workload.storage.subtypes.${ type }`)
) {
return this.t(`workload.storage.subtypes.${ type }`);
} else {
return type;
}
},
openPopover() {
const button = this.$refs.buttonDropdown;
try {
button.togglePopover();
} catch (e) {}
},
},
};
</script>
<template>
<div>
<!-- Storage Volumes -->
<ArrayListGrouped
:key="selectedContainerVolumes.length"
v-model="selectedContainerVolumes"
:mode="mode"
@remove="removeVolume"
>
<!-- Custom/default storage volume form -->
<template #default="props">
<h3>{{ props.row.value.name }} ({{ headerFor(props.row.value) }})</h3>
<Mount
:container="container"
:name="props.row.value.name"
:mode="mode"
/>
</template>
<!-- Add Storage Volume -->
<template #add>
<ButtonDropdown
v-if="!isView"
id="add-volume"
:button-label="t('workload.storage.selectVolume')"
:dropdown-options="availableVolumeOptions"
size="sm"
@click-action="e=>selectVolume(e)"
>
<template #no-options>
{{ t('workload.storage.noVolumes') }}
</template>
</ButtonDropdown>
</template>
</ArrayListGrouped>
</div>
</template>