mirror of https://github.com/rancher/dashboard.git
358 lines
9.4 KiB
Vue
358 lines
9.4 KiB
Vue
<script>
|
|
/**
|
|
* The Route and Receiver resources are deprecated. Going forward,
|
|
* routes and receivers should be configured within AlertmanagerConfigs.
|
|
* Any updates to receiver configuration forms, such as Slack/email/PagerDuty
|
|
* etc, should be made to the receiver forms that are based on the
|
|
* AlertmanagerConfig resource, which has a different API. The new forms are
|
|
* located in @shell/edit/monitoring.coreos.com.alertmanagerconfig/types.
|
|
*/
|
|
import { MONITORING } from '@shell/config/types';
|
|
import ArrayListGrouped from '@shell/components/form/ArrayListGrouped';
|
|
import Loading from '@shell/components/Loading';
|
|
import { Banner } from '@components/Banner';
|
|
import CruResource from '@shell/components/CruResource';
|
|
import { LabeledInput } from '@components/Form/LabeledInput';
|
|
import Tabbed from '@shell/components/Tabbed';
|
|
import Tab from '@shell/components/Tabbed/Tab';
|
|
import YamlEditor, { EDITOR_MODES } from '@shell/components/YamlEditor';
|
|
import CreateEditView from '@shell/mixins/create-edit-view';
|
|
import jsyaml from 'js-yaml';
|
|
import { RECEIVERS_TYPES } from '@shell/models/monitoring.coreos.com.receiver';
|
|
import ButtonDropdown from '@shell/components/ButtonDropdown';
|
|
import { _EDIT, _VIEW } from '@shell/config/query-params';
|
|
|
|
export default {
|
|
components: {
|
|
ArrayListGrouped,
|
|
Banner,
|
|
ButtonDropdown,
|
|
CruResource,
|
|
LabeledInput,
|
|
Loading,
|
|
Tabbed,
|
|
Tab,
|
|
YamlEditor
|
|
},
|
|
|
|
mixins: [CreateEditView],
|
|
|
|
inheritAttrs: false,
|
|
|
|
async fetch() {
|
|
await this.$store.dispatch('cluster/findAll', { type: MONITORING.SPOOFED.ROUTE });
|
|
},
|
|
|
|
data() {
|
|
this.value['spec'] = this.value.spec || {};
|
|
|
|
if (this.mode === _EDIT || this.mode === _VIEW) {
|
|
for (let i = 0; i < this.value.spec.email_configs.length; i++) {
|
|
if (this.value.spec.email_configs[i].smarthost) {
|
|
const hostPort = this.value.spec.email_configs[i].smarthost.split(':');
|
|
|
|
this.value.spec.email_configs[i]['host'] = hostPort[0] || '';
|
|
this.value.spec.email_configs[i]['port'] = hostPort[1] || '';
|
|
delete this.value.spec.email_configs[i]['smarthost'];
|
|
}
|
|
}
|
|
}
|
|
|
|
RECEIVERS_TYPES.forEach((receiverType) => {
|
|
this.value.spec[receiverType.key] = this.value.spec[receiverType.key] || [];
|
|
});
|
|
|
|
const specSchema = this.$store.getters['cluster/schemaFor'](MONITORING.SPOOFED.RECEIVER_SPEC);
|
|
const expectedFields = Object.keys(specSchema.resourceFields);
|
|
const suffix = {};
|
|
|
|
Object.keys(this.value.spec).forEach((key) => {
|
|
if (!expectedFields.includes(key)) {
|
|
suffix[key] = this.value.spec[key];
|
|
}
|
|
});
|
|
|
|
let suffixYaml = jsyaml.dump(suffix);
|
|
|
|
if (suffixYaml.trim() === '{}') {
|
|
suffixYaml = '';
|
|
}
|
|
|
|
return {
|
|
expectedFields,
|
|
receiverTypes: RECEIVERS_TYPES,
|
|
fileFound: false,
|
|
receiver: {},
|
|
suffixYaml,
|
|
EDITOR_MODES,
|
|
yamlError: '',
|
|
doneLocationOverride: {
|
|
name: 'c-cluster-monitoring-route-receiver',
|
|
params: { cluster: this.$store.getters['clusterId'] },
|
|
query: { resource: MONITORING.SPOOFED.RECEIVER }
|
|
}
|
|
};
|
|
},
|
|
|
|
computed: {
|
|
editorMode() {
|
|
if ( this.isView ) {
|
|
return EDITOR_MODES.VIEW_CODE;
|
|
}
|
|
|
|
return EDITOR_MODES.EDIT_CODE;
|
|
},
|
|
},
|
|
|
|
watch: {
|
|
suffixYaml(value) {
|
|
try {
|
|
// We need this step so we don't just keep adding new keys when modifying the custom field
|
|
Object.keys(this.value.spec).forEach((key) => {
|
|
if (!this.expectedFields.includes(key)) {
|
|
delete this.value.spec[key];
|
|
}
|
|
});
|
|
|
|
const suffix = jsyaml.load(value);
|
|
|
|
Object.assign(this.value.spec, suffix);
|
|
this.yamlError = '';
|
|
} catch (ex) {
|
|
this.yamlError = `There was a problem parsing the Custom Config: ${ ex }`;
|
|
}
|
|
}
|
|
},
|
|
|
|
methods: {
|
|
getComponent(name) {
|
|
return require(`./types/${ name }`).default;
|
|
},
|
|
|
|
navigateTo(receiverType) {
|
|
this.$refs.tabbed.select(receiverType.name);
|
|
},
|
|
|
|
getCount(receiverType) {
|
|
const found = this.value?.spec?.[receiverType.key] || [];
|
|
|
|
return found.length;
|
|
},
|
|
|
|
tabChanged({ tab }) {
|
|
window.scrollTop = 0;
|
|
if ( tab.name === 'custom' ) {
|
|
this.$nextTick(() => {
|
|
if ( this.$refs.customEditor ) {
|
|
this.$refs.customEditor[0].refresh();
|
|
this.$refs.customEditor[0].focus();
|
|
}
|
|
});
|
|
}
|
|
},
|
|
|
|
saveOverride(buttonDone) {
|
|
if (this.yamlError) {
|
|
this.errors = this.errors || [];
|
|
this.errors.push(this.yamlError);
|
|
buttonDone(false);
|
|
} else {
|
|
this.save(...arguments);
|
|
}
|
|
},
|
|
|
|
createAddOptions(receiverType) {
|
|
return receiverType.addOptions.map();
|
|
},
|
|
|
|
createSmarthost() {
|
|
if (this.value.spec.email_configs.length > 0) {
|
|
this.value.spec.email_configs.forEach((email) => {
|
|
if (email['port'] || email['host']) {
|
|
const hostValue = email.host ? `${ email.host }` : '';
|
|
|
|
email.smarthost = email.port ? `${ hostValue }:${ email.port }` : `${ hostValue }`;
|
|
delete email['port'];
|
|
delete email['host'];
|
|
}
|
|
});
|
|
}
|
|
}
|
|
},
|
|
|
|
created() {
|
|
this.registerBeforeHook(this.createSmarthost, 'create-smarthost');
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<Loading v-if="$fetchState.pending" />
|
|
<CruResource
|
|
v-else
|
|
class="receiver"
|
|
:done-route="doneRoute"
|
|
:mode="mode"
|
|
:resource="value"
|
|
:subtypes="[]"
|
|
:can-yaml="false"
|
|
:errors="errors"
|
|
:cancel-event="true"
|
|
@error="e=>errors = e"
|
|
@finish="saveOverride"
|
|
@cancel="done"
|
|
>
|
|
<div
|
|
v-if="!isView"
|
|
class="row mb-10"
|
|
>
|
|
<div class="col span-6">
|
|
<LabeledInput
|
|
v-model:value="value.spec.name"
|
|
:disabled="!isCreate"
|
|
:label="t('generic.name')"
|
|
:mode="mode"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<Tabbed
|
|
ref="tabbed"
|
|
:side-tabs="true"
|
|
default-tab="overview"
|
|
@changed="tabChanged"
|
|
>
|
|
<Tab
|
|
:label="t('generic.overview')"
|
|
:weight="receiverTypes.length"
|
|
name="overview"
|
|
>
|
|
<div class="box-container create-resource-container ">
|
|
<div
|
|
v-for="(receiverType, i) in receiverTypes"
|
|
:key="i"
|
|
class="mb-10 subtype-banner"
|
|
primary-color-var="--primary-color"
|
|
@click="navigateTo(receiverType)"
|
|
>
|
|
<div class="left">
|
|
<div class="logo">
|
|
<img :src="receiverType.logo">
|
|
</div>
|
|
<h4 class="name ml-10">
|
|
<t :k="receiverType.label" />
|
|
</h4>
|
|
</div>
|
|
<div
|
|
v-if="receiverType.name !== 'custom'"
|
|
class="right"
|
|
>
|
|
{{ getCount(receiverType) }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Tab>
|
|
<Tab
|
|
v-for="(receiverType, i) in receiverTypes"
|
|
:key="i"
|
|
:label="t(receiverType.label)"
|
|
:name="receiverType.name"
|
|
:weight="receiverTypes.length - i"
|
|
>
|
|
<YamlEditor
|
|
v-if="receiverType.name === 'custom'"
|
|
ref="customEditor"
|
|
v-model:value="suffixYaml"
|
|
:scrolling="false"
|
|
:editor-mode="editorMode"
|
|
/>
|
|
<div v-else>
|
|
<component
|
|
:is="getComponent(receiverType.banner)"
|
|
v-if="receiverType.banner"
|
|
:model="value.spec[receiverType.key]"
|
|
:mode="mode"
|
|
/>
|
|
<ArrayListGrouped
|
|
v-model:value="value.spec[receiverType.key]"
|
|
class="namespace-list"
|
|
:mode="mode"
|
|
:default-add-value="{}"
|
|
:add-label="t('monitoringReceiver.addButton', { type: t(receiverType.label) })"
|
|
>
|
|
<template #default="props">
|
|
<component
|
|
:is="getComponent(receiverType.name)"
|
|
:value="props.row.value"
|
|
:mode="mode"
|
|
/>
|
|
</template>
|
|
<template
|
|
v-if="receiverType.addButton"
|
|
#add
|
|
>
|
|
<component
|
|
:is="getComponent(receiverType.addButton)"
|
|
:model="value.spec[receiverType.key]"
|
|
:mode="mode"
|
|
/>
|
|
</template>
|
|
</ArrayListGrouped>
|
|
</div>
|
|
</Tab>
|
|
</Tabbed>
|
|
</CruResource>
|
|
</template>
|
|
|
|
<style lang="scss">
|
|
.receiver {
|
|
$margin: 10px;
|
|
$logo: 60px;
|
|
|
|
.box-container {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
flex-wrap: wrap;
|
|
margin: 0 -1*$margin;
|
|
|
|
.subtype-banner{
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
flex-direction: row;
|
|
}
|
|
}
|
|
|
|
.right {
|
|
padding: 30px;
|
|
border-left: 1px solid var(--border);
|
|
}
|
|
|
|
.logo {
|
|
text-align: center;
|
|
width: $logo;
|
|
height: $logo;
|
|
border-radius: calc(2 * var(--border-radius));
|
|
overflow: hidden;
|
|
background-color: white;
|
|
display: inline-block;
|
|
vertical-align: middle;
|
|
|
|
img {
|
|
width: $logo - 4px;
|
|
height: $logo - 4px;
|
|
object-fit: contain;
|
|
position: relative;
|
|
top: 2px;
|
|
}
|
|
}
|
|
|
|
.name {
|
|
white-space: nowrap;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
margin-bottom: 0;
|
|
display: inline-block;
|
|
vertical-align: middle;
|
|
}
|
|
}
|
|
</style>
|