mirror of https://github.com/rancher/dashboard.git
Monitoring UI Polish - Overview & Create Route
rancher/dashboard#1986 update receiver tabs and labeled tooltips fix styling on receiver responder rows
This commit is contained in:
parent
a4aaf62034
commit
534e0a982b
|
|
@ -25,6 +25,7 @@
|
|||
@import "./global/tooltip";
|
||||
@import "./global/table";
|
||||
@import "./global/select";
|
||||
@import "./global/resource";
|
||||
|
||||
@import "./vendor/vue-select";
|
||||
@import "./vendor/vue-js-modal";
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
.create-resource-container {
|
||||
.subtypes-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: 100%;
|
||||
}
|
||||
.subtype-content {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.subtype-banner {
|
||||
border-left: 5px solid var(--primary);
|
||||
border-radius: var(--border-radius);
|
||||
display: flex;
|
||||
flex-basis: 40%;
|
||||
margin: 10px;
|
||||
min-height: 100px;
|
||||
padding: 10px;
|
||||
box-shadow: 0 0 20px var(--shadow);
|
||||
|
||||
&.disabled {
|
||||
cursor: not-allowed !important;
|
||||
background-color: var(--disabled-bg);
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background-color: var(--accent-btn);
|
||||
}
|
||||
|
||||
&.top {
|
||||
background-image: linear-gradient(
|
||||
-90deg,
|
||||
var(--body-bg),
|
||||
var(--accent-btn)
|
||||
);
|
||||
|
||||
h2 {
|
||||
margin: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
||||
h5 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.flex-right {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
color: var(--input-label);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&:not(.top) {
|
||||
align-items: top;
|
||||
flex-direction: row;
|
||||
justify-content: start;
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
box-shadow: 0px 0px 1px var(--outline-width) var(--outline);
|
||||
}
|
||||
}
|
||||
|
||||
.round-image {
|
||||
border-radius: 50%;
|
||||
height: 50px;
|
||||
margin-right: 10px;
|
||||
width: 50px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.banner-abbrv {
|
||||
align-items: center;
|
||||
background-color: var(--primary);
|
||||
color: white;
|
||||
display: flex;
|
||||
font-size: 2.5em;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1119,6 +1119,32 @@ monitoring:
|
|||
block: Block
|
||||
file: Filesystem
|
||||
|
||||
monitoringReceiver:
|
||||
addButton: Add {type}
|
||||
custom:
|
||||
label: Custom
|
||||
title: Custom Config
|
||||
info: The YAML provided here will be directly appended to your receiver within the Alertmanager Config Secret.
|
||||
email:
|
||||
label: Email
|
||||
title: Email Config
|
||||
opsgenie:
|
||||
label: Opsgenie
|
||||
title: Opsgenie Config
|
||||
pagerduty:
|
||||
label: PagerDuty
|
||||
title: PagerDuty Config
|
||||
info: "You can find additional info on creating an Integration Key for PagerDuty <a href='https://www.pagerduty.com/docs/guides/prometheus-integration-guide/' target='_blank' rel='noopener nofollow' class='flex-right'>here</a>."
|
||||
slack:
|
||||
label: Slack
|
||||
title: Slack Config
|
||||
info: "You can find additional info on creating Incoming Webhooks for Slack <a href='https://rancher.slack.com/apps/A0F7XDUAZ-incoming-webhooks' target='_blank' rel='noopener noreferrer nofollow'>here</a> ."
|
||||
webhook:
|
||||
label: Webhook
|
||||
title: Webhook Config
|
||||
|
||||
|
||||
|
||||
monitoringRoute:
|
||||
groups:
|
||||
label: Group By
|
||||
|
|
|
|||
|
|
@ -359,7 +359,7 @@ export default {
|
|||
</section>
|
||||
</template>
|
||||
|
||||
<style lang='scss'>
|
||||
<style lang='scss' scoped>
|
||||
.cru-resource-yaml-container {
|
||||
.resource-yaml {
|
||||
.yaml-editor {
|
||||
|
|
@ -367,96 +367,12 @@ export default {
|
|||
}
|
||||
}
|
||||
}
|
||||
.subtypes-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: 100%;
|
||||
.create-resource-container {
|
||||
.subtype-banner {
|
||||
.round-image {
|
||||
background-color: var(--primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.subtype-content {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.subtype-banner {
|
||||
border-left: 5px solid var(--primary);
|
||||
border-radius: var(--border-radius);
|
||||
display: flex;
|
||||
flex-basis: 40%;
|
||||
margin: 10px;
|
||||
min-height: 100px;
|
||||
padding: 10px;
|
||||
box-shadow: 0 0 20px var(--shadow);
|
||||
|
||||
&.selected {
|
||||
background-color: var(--accent-btn);
|
||||
}
|
||||
|
||||
&.top {
|
||||
background-image: linear-gradient(
|
||||
-90deg,
|
||||
var(--body-bg),
|
||||
var(--accent-btn)
|
||||
);
|
||||
|
||||
H2 {
|
||||
margin: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
// flex-basis: 10%;
|
||||
|
||||
h5 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.flex-right {
|
||||
margin-left: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.description {
|
||||
color: var(--input-label);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.description {
|
||||
color: var(--input-label);
|
||||
}
|
||||
|
||||
&:not(.top) {
|
||||
align-items: top;
|
||||
flex-direction: row;
|
||||
justify-content: start;
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
box-shadow: 0px 0px 1px var(--outline-width) var(--outline);
|
||||
}
|
||||
}
|
||||
|
||||
.round-image {
|
||||
background-color: var(--primary);
|
||||
border-radius: 50%;
|
||||
height: 50px;
|
||||
margin-right: 10px;
|
||||
width: 50px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.banner-abbrv {
|
||||
align-items: center;
|
||||
background-color: var(--primary);
|
||||
color: white;
|
||||
display: flex;
|
||||
font-size: 2.5em;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -22,8 +22,8 @@ export default {
|
|||
},
|
||||
|
||||
tooltip: {
|
||||
type: String,
|
||||
default: null,
|
||||
type: [String, Object]
|
||||
},
|
||||
|
||||
hoverTooltip: {
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ export default {
|
|||
},
|
||||
tooltip: {
|
||||
default: null,
|
||||
type: String
|
||||
type: [String, Object]
|
||||
},
|
||||
value: {
|
||||
default: null,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
export default {
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
type: [String, Object],
|
||||
default: null
|
||||
},
|
||||
|
||||
|
|
@ -22,7 +22,7 @@ export default {
|
|||
<template>
|
||||
<div ref="container" class="labeled-tooltip" :class="{[status]: true, hoverable: hover}">
|
||||
<template v-if="hover">
|
||||
<i v-tooltip="{content: value, classes: [`tooltip-${status}`]}" :class="{'hover':!value}" class="icon icon-info status-icon" />
|
||||
<i v-tooltip="value.content ? { ...{content: value.content, classes: [`tooltip-${status}`]}, ...value } : value" :class="{'hover':!value}" class="icon icon-info status-icon" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<i :class="{'hover':!value}" class="icon icon-info status-icon" />
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ export default {
|
|||
<img :src="receiverType.logo" />
|
||||
</div>
|
||||
<h4 class="name ml-10">
|
||||
{{ receiverType.label }}
|
||||
<t :k="receiverType.label" />
|
||||
</h4>
|
||||
</div>
|
||||
<div v-if="receiverType.name !== 'custom'" class="right">
|
||||
|
|
@ -175,14 +175,13 @@ export default {
|
|||
</GradientBox>
|
||||
</div>
|
||||
</Tab>
|
||||
<Tab v-for="(receiverType, i) in receiverTypes" :key="i" :label="receiverType.label" :name="receiverType.name" :weight="receiverTypes.length - i">
|
||||
<Banner v-if="receiverType.name === 'slack'" color="info">
|
||||
Here's how you create <a href="https://rancher.slack.com/apps/A0F7XDUAZ-incoming-webhooks" target="_blank" rel="noopener noreferrer nofollow">Incoming Webhooks</a> for Slack.
|
||||
</Banner>
|
||||
<Banner v-if="!isView && receiverType.name === 'custom'" color="info" label="The YAML provided here will be directly appended to your receiver within the Alertmanager Config Secret" />
|
||||
<Banner v-if="!isView && receiverType.name === 'pagerduty'" color="info">
|
||||
Here's how you create an <a href="https://www.pagerduty.com/docs/guides/prometheus-integration-guide/" target="_blank" rel="noopener nofollow" class="flex-right">Integration Key</a> for PagerDuty
|
||||
</Banner>
|
||||
<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"
|
||||
|
|
@ -196,8 +195,7 @@ export default {
|
|||
class="namespace-list"
|
||||
:mode="mode"
|
||||
:default-add-value="{}"
|
||||
:disabled="disabled"
|
||||
:add-label="'Add ' + receiverType.label"
|
||||
:add-label="t('monitoringReceiver.addButton', { type: t(receiverType.label) })"
|
||||
>
|
||||
<template #default="props">
|
||||
<div :class="{'pt-30': !isView}">
|
||||
|
|
|
|||
|
|
@ -1,191 +1,198 @@
|
|||
<script>
|
||||
import ArrayList from '@/components/form/ArrayList';
|
||||
import LabeledInput from '@/components/form/LabeledInput';
|
||||
import LabeledSelect from '@/components/form/LabeledSelect';
|
||||
import Checkbox from '@/components/form/Checkbox';
|
||||
import InputWithSelect from '@/components/form/InputWithSelect';
|
||||
import { _VIEW } from '@/config/query-params';
|
||||
|
||||
export const TARGETS = [
|
||||
{
|
||||
label: 'Id',
|
||||
value: 'id'
|
||||
},
|
||||
{
|
||||
label: 'Name',
|
||||
value: 'name'
|
||||
},
|
||||
{
|
||||
label: 'Username',
|
||||
value: 'username'
|
||||
}
|
||||
];
|
||||
|
||||
export const TYPES = [
|
||||
{
|
||||
label: 'Team',
|
||||
value: 'team'
|
||||
},
|
||||
{
|
||||
label: 'User',
|
||||
value: 'user'
|
||||
},
|
||||
{
|
||||
label: 'Escalation',
|
||||
value: 'escalation'
|
||||
},
|
||||
{
|
||||
label: 'Schedule',
|
||||
value: 'schedule'
|
||||
}
|
||||
];
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ArrayList, Checkbox, InputWithSelect, LabeledInput, LabeledSelect
|
||||
},
|
||||
props: {
|
||||
mode: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
value: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
this.$set(this.value, 'http_config', this.value.http_config || {});
|
||||
this.$set(this.value, 'send_resolved', typeof this.value.send_resolved === 'boolean' ? this.value.send_resolved : true);
|
||||
this.$set(this.value, 'responders', this.value.responders || []);
|
||||
|
||||
const responders = this.value.responders.map((responder) => {
|
||||
const target = TARGETS.find(target => responder[target.value]);
|
||||
|
||||
return {
|
||||
type: responder.type,
|
||||
target: target.value,
|
||||
value: responder[target.value]
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
defaultResponder: {
|
||||
type: TYPES[0].value,
|
||||
target: TARGETS[0].value,
|
||||
value: ''
|
||||
},
|
||||
responders,
|
||||
TARGETS,
|
||||
TYPES
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
isView() {
|
||||
return this.mode === _VIEW;
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
responders: {
|
||||
deep: true,
|
||||
handler() {
|
||||
const responders = this.responders.map((responder) => {
|
||||
return {
|
||||
type: responder.type,
|
||||
[responder.target]: responder.value
|
||||
};
|
||||
});
|
||||
|
||||
this.$set(this.value, 'responders', responders);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
updateResponder({ selected, text }, row) {
|
||||
row.target = selected;
|
||||
row.value = text;
|
||||
},
|
||||
typeLabel(type) {
|
||||
return TYPES.find(t => t.value === type).label;
|
||||
},
|
||||
targetLabel(target) {
|
||||
return TARGETS.find(t => t.value === target).label;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="row mb-20">
|
||||
<div class="col span-12">
|
||||
<LabeledInput v-model="value.api_key" :mode="mode" label="API Key" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-20">
|
||||
<div class="col span-12">
|
||||
<LabeledInput v-model="value.http_config.proxy_url" :mode="mode" label="Proxy URL" placeholder="e.g. http://my-proxy/" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-20">
|
||||
<Checkbox v-model="value.send_resolved" :mode="mode" label="Enable send resolved alerts" />
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col span-12">
|
||||
<h3>Responders</h3>
|
||||
<ArrayList v-model="responders" :mode="mode" :default-add-value="defaultResponder" :show-header="true">
|
||||
<template v-slot:column-headers>
|
||||
<div class="row" :class="{'mb-15': isView}">
|
||||
<div class="col span-6">
|
||||
<span class="text-label">Type</span>
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<span class="text-label">Send To</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot:columns="scope">
|
||||
<div class="row responder">
|
||||
<div class="col span-6">
|
||||
<span v-if="isView">{{ typeLabel(scope.row.value.type) }}</span>
|
||||
<LabeledSelect v-else v-model="scope.row.value.type" :mode="mode" label="Type" :options="TYPES" />
|
||||
</div>
|
||||
<div class="col-span-6 target">
|
||||
<span v-if="isView">{{ targetLabel(scope.row.value.target) }}: {{ scope.row.value.value }}</span>
|
||||
<InputWithSelect
|
||||
v-else
|
||||
:mode="mode"
|
||||
:options="TARGETS"
|
||||
:select-value="scope.row.value.target"
|
||||
:text-value="scope.row.value.value"
|
||||
@input="updateResponder($event, scope.row.value)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</ArrayList>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.responder {
|
||||
&, .target {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.target ::v-deep {
|
||||
& .input-container {
|
||||
height: $input-height;
|
||||
}
|
||||
|
||||
& .unlabeled-select {
|
||||
min-width: 35%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
import ArrayList from '@/components/form/ArrayList';
|
||||
import LabeledInput from '@/components/form/LabeledInput';
|
||||
import Select from '@/components/form/Select';
|
||||
import Checkbox from '@/components/form/Checkbox';
|
||||
import InputWithSelect from '@/components/form/InputWithSelect';
|
||||
import { _VIEW } from '@/config/query-params';
|
||||
|
||||
export const TARGETS = [
|
||||
{
|
||||
label: 'Id',
|
||||
value: 'id'
|
||||
},
|
||||
{
|
||||
label: 'Name',
|
||||
value: 'name'
|
||||
},
|
||||
{
|
||||
label: 'Username',
|
||||
value: 'username'
|
||||
}
|
||||
];
|
||||
|
||||
export const TYPES = [
|
||||
{
|
||||
label: 'Team',
|
||||
value: 'team'
|
||||
},
|
||||
{
|
||||
label: 'User',
|
||||
value: 'user'
|
||||
},
|
||||
{
|
||||
label: 'Escalation',
|
||||
value: 'escalation'
|
||||
},
|
||||
{
|
||||
label: 'Schedule',
|
||||
value: 'schedule'
|
||||
}
|
||||
];
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ArrayList, Checkbox, InputWithSelect, LabeledInput, Select
|
||||
},
|
||||
props: {
|
||||
mode: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
value: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
this.$set(this.value, 'http_config', this.value.http_config || {});
|
||||
this.$set(this.value, 'send_resolved', typeof this.value.send_resolved === 'boolean' ? this.value.send_resolved : true);
|
||||
this.$set(this.value, 'responders', this.value.responders || []);
|
||||
|
||||
const responders = this.value.responders.map((responder) => {
|
||||
const target = TARGETS.find(target => responder[target.value]);
|
||||
|
||||
return {
|
||||
type: responder.type,
|
||||
target: target.value,
|
||||
value: responder[target.value]
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
defaultResponder: {
|
||||
type: TYPES[0].value,
|
||||
target: TARGETS[0].value,
|
||||
value: ''
|
||||
},
|
||||
responders,
|
||||
TARGETS,
|
||||
TYPES
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
isView() {
|
||||
return this.mode === _VIEW;
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
responders: {
|
||||
deep: true,
|
||||
handler() {
|
||||
const responders = this.responders.map((responder) => {
|
||||
return {
|
||||
type: responder.type,
|
||||
[responder.target]: responder.value
|
||||
};
|
||||
});
|
||||
|
||||
this.$set(this.value, 'responders', responders);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
updateResponder({ selected, text }, row) {
|
||||
row.target = selected;
|
||||
row.value = text;
|
||||
},
|
||||
typeLabel(type) {
|
||||
return TYPES.find(t => t.value === type).label;
|
||||
},
|
||||
targetLabel(target) {
|
||||
return TARGETS.find(t => t.value === target).label;
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="row mb-20">
|
||||
<div class="col span-12">
|
||||
<LabeledInput v-model="value.api_key" :mode="mode" label="API Key" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-20">
|
||||
<div class="col span-12">
|
||||
<LabeledInput v-model="value.http_config.proxy_url" :mode="mode" label="Proxy URL" placeholder="e.g. http://my-proxy/" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-20">
|
||||
<Checkbox v-model="value.send_resolved" :mode="mode" label="Enable send resolved alerts" />
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col span-12">
|
||||
<h3>Responders</h3>
|
||||
<ArrayList v-model="responders" :mode="mode" :default-add-value="defaultResponder" :show-header="true">
|
||||
<template v-slot:column-headers>
|
||||
<div class="row mb-10">
|
||||
<div class="col span-6">
|
||||
<span class="text-label">Type</span>
|
||||
</div>
|
||||
<div class="col span-6 send-to">
|
||||
<span class="text-label">Send To</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template v-slot:columns="scope">
|
||||
<div class="row responder">
|
||||
<div class="col span-6">
|
||||
<span v-if="isView">{{ typeLabel(scope.row.value.type) }}</span>
|
||||
<Select v-else v-model="scope.row.value.type" :mode="mode" label="Type" :options="TYPES" />
|
||||
</div>
|
||||
<div class="col-span-6 target">
|
||||
<span v-if="isView">{{ targetLabel(scope.row.value.target) }}: {{ scope.row.value.value }}</span>
|
||||
<InputWithSelect
|
||||
v-else
|
||||
:mode="mode"
|
||||
:options="TARGETS"
|
||||
:select-value="scope.row.value.target"
|
||||
:text-value="scope.row.value.value"
|
||||
@input="updateResponder($event, scope.row.value)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</ArrayList>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.responder {
|
||||
&, .target {
|
||||
width: 100%;
|
||||
}
|
||||
.send-to {
|
||||
margin-left: -35px;
|
||||
}
|
||||
|
||||
.unlabeled-select ::v-deep {
|
||||
height: $input-height;
|
||||
}
|
||||
|
||||
.target ::v-deep {
|
||||
& .input-container {
|
||||
height: $input-height;
|
||||
}
|
||||
|
||||
& .unlabeled-select {
|
||||
min-width: 35%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,66 +1,88 @@
|
|||
<script>
|
||||
import LabeledInput from '@/components/form/LabeledInput';
|
||||
import LabeledSelect from '@/components/form/LabeledSelect';
|
||||
import Checkbox from '@/components/form/Checkbox';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Checkbox, LabeledInput, LabeledSelect
|
||||
},
|
||||
props: {
|
||||
mode: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
value: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
this.$set(this.value, 'http_config', this.value.http_config || {});
|
||||
this.$set(this.value, 'send_resolved', typeof this.value.send_resolved === 'boolean' ? this.value.send_resolved : true);
|
||||
|
||||
const integrationMapping = {
|
||||
'Events API v2': 'routing_key',
|
||||
Prometheus: 'service_key'
|
||||
};
|
||||
|
||||
const integrationTypeOptions = Object.keys(integrationMapping);
|
||||
|
||||
return {
|
||||
integrationMapping,
|
||||
integrationTypeOptions,
|
||||
integrationType: this.value.routing_key ? integrationTypeOptions[0] : integrationTypeOptions[1]
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
integrationType() {
|
||||
this.integrationTypeOptions.forEach((option) => {
|
||||
this.value[this.integrationMapping[option]] = null;
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="row mb-20">
|
||||
<div class="col span-6">
|
||||
<LabeledSelect v-model="integrationType" :options="integrationTypeOptions" :mode="mode" label="Integration Type" />
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<LabeledInput v-model="value[integrationMapping[integrationType]]" :mode="mode" label="Default Integration Key" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-20">
|
||||
<div class="col span-12">
|
||||
<LabeledInput v-model="value.http_config.proxy_url" :mode="mode" label="Proxy URL" placeholder="e.g. http://my-proxy/" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<Checkbox v-model="value.send_resolved" :mode="mode" label="Enable send resolved alerts" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import LabeledInput from '@/components/form/LabeledInput';
|
||||
import LabeledSelect from '@/components/form/LabeledSelect';
|
||||
import Checkbox from '@/components/form/Checkbox';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Checkbox,
|
||||
LabeledInput,
|
||||
LabeledSelect,
|
||||
},
|
||||
props: {
|
||||
mode: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
value: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
this.$set(this.value, 'http_config', this.value.http_config || {});
|
||||
this.$set(this.value, 'send_resolved', typeof this.value.send_resolved === 'boolean' ? this.value.send_resolved : true);
|
||||
|
||||
const integrationMapping = {
|
||||
'Events API v2': 'routing_key',
|
||||
Prometheus: 'service_key',
|
||||
};
|
||||
|
||||
const integrationTypeOptions = Object.keys(integrationMapping);
|
||||
|
||||
return {
|
||||
integrationMapping,
|
||||
integrationTypeOptions,
|
||||
integrationType: this.value.routing_key ? integrationTypeOptions[0] : integrationTypeOptions[1]
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
integrationType() {
|
||||
this.integrationTypeOptions.forEach((option) => {
|
||||
this.value[this.integrationMapping[option]] = null;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<div class="row mb-20">
|
||||
<div class="col span-6">
|
||||
<LabeledSelect
|
||||
v-model="integrationType"
|
||||
:options="integrationTypeOptions"
|
||||
:mode="mode"
|
||||
:tooltip="{ content: t('monitoringReceiver.pagerduty.info', {}, raw=true), autoHide: false}"
|
||||
:hover-tooltip="true"
|
||||
label="Integration Type"
|
||||
/>
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<LabeledInput
|
||||
v-model="value[integrationMapping[integrationType]]"
|
||||
:mode="mode"
|
||||
label="Default Integration Key"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-20">
|
||||
<div class="col span-12">
|
||||
<LabeledInput
|
||||
v-model="value.http_config.proxy_url"
|
||||
:mode="mode"
|
||||
label="Proxy URL"
|
||||
placeholder="e.g. http://my-proxy/"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<Checkbox
|
||||
v-model="value.send_resolved"
|
||||
:mode="mode"
|
||||
label="Enable send resolved alerts"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -12,15 +12,19 @@ export default {
|
|||
},
|
||||
value: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
this.$set(this.value, 'http_config', this.value.http_config || {});
|
||||
this.$set(this.value, 'send_resolved', this.value.send_resolved || false);
|
||||
|
||||
if (this.mode === _CREATE) {
|
||||
this.$set(this.value, 'text', this.value.text || '{{ template "slack.rancher.text" . }}');
|
||||
this.$set(
|
||||
this.value,
|
||||
'text',
|
||||
this.value.text || '{{ template "slack.rancher.text" . }}'
|
||||
);
|
||||
}
|
||||
|
||||
return {};
|
||||
|
|
@ -32,19 +36,39 @@ export default {
|
|||
<div>
|
||||
<div class="row mb-20">
|
||||
<div class="col span-12">
|
||||
<LabeledInput v-model="value.api_url" :mode="mode" label="URL" placeholder="e.g. https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX" />
|
||||
<LabeledInput
|
||||
v-model="value.api_url"
|
||||
:mode="mode"
|
||||
label="Webhook URL"
|
||||
:tooltip="{ content: t('monitoringReceiver.slack.info', {}, raw=true), autoHide: false}"
|
||||
placeholder="e.g. https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-20">
|
||||
<div class="col span-6">
|
||||
<LabeledInput v-model="value.channel" :mode="mode" label="Default Channel" placeholder="e.g. #example" />
|
||||
<LabeledInput
|
||||
v-model="value.channel"
|
||||
:mode="mode"
|
||||
label="Default Channel"
|
||||
placeholder="e.g. #example"
|
||||
/>
|
||||
</div>
|
||||
<div class="col span-6">
|
||||
<LabeledInput v-model="value.http_config.proxy_url" :mode="mode" label="Proxy URL" placeholder="e.g. http://my-proxy/" />
|
||||
<LabeledInput
|
||||
v-model="value.http_config.proxy_url"
|
||||
:mode="mode"
|
||||
label="Proxy URL"
|
||||
placeholder="e.g. http://my-proxy/"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<Checkbox v-model="value.send_resolved" :mode="mode" label="Enable send resolved alerts" />
|
||||
<Checkbox
|
||||
v-model="value.send_resolved"
|
||||
:mode="mode"
|
||||
label="Enable send resolved alerts"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -6,43 +6,46 @@ import jsyaml from 'js-yaml';
|
|||
export const RECEIVERS_TYPES = [
|
||||
{
|
||||
name: 'slack',
|
||||
label: 'Slack',
|
||||
title: 'Slack Config',
|
||||
label: 'monitoringReceiver.slack.label',
|
||||
title: 'monitoringReceiver.slack.title',
|
||||
info: 'monitoringReceiver.slack.info',
|
||||
key: 'slack_configs',
|
||||
logo: require(`~/assets/images/vendor/slack.svg`)
|
||||
},
|
||||
{
|
||||
name: 'email',
|
||||
label: 'Email',
|
||||
title: 'Email Config',
|
||||
label: 'monitoringReceiver.email.label',
|
||||
title: 'monitoringReceiver.email.title',
|
||||
key: 'email_configs',
|
||||
logo: require(`~/assets/images/vendor/email.svg`)
|
||||
},
|
||||
{
|
||||
name: 'pagerduty',
|
||||
label: 'PagerDuty',
|
||||
title: 'PagerDuty Config',
|
||||
label: 'monitoringReceiver.pagerduty.label',
|
||||
title: 'monitoringReceiver.pagerduty.title',
|
||||
info: 'monitoringReceiver.pagerduty.info',
|
||||
key: 'pagerduty_configs',
|
||||
logo: require(`~/assets/images/vendor/pagerduty.svg`)
|
||||
},
|
||||
{
|
||||
name: 'opsgenie',
|
||||
label: 'Opsgenie',
|
||||
title: 'Opsgenie Config',
|
||||
label: 'monitoringReceiver.opsgenie.label',
|
||||
title: 'monitoringReceiver.opsgenie.title',
|
||||
key: 'opsgenie_configs',
|
||||
logo: require(`~/assets/images/vendor/email.svg`)
|
||||
},
|
||||
{
|
||||
name: 'webhook',
|
||||
label: 'Webhook',
|
||||
title: 'Webhook Config',
|
||||
label: 'monitoringReceiver.webhook.label',
|
||||
title: 'monitoringReceiver.webhook.title',
|
||||
key: 'webhook_configs',
|
||||
logo: require(`~/assets/images/vendor/webhook.svg`)
|
||||
},
|
||||
{
|
||||
name: 'custom',
|
||||
label: 'Custom',
|
||||
title: 'Custom Config',
|
||||
label: 'monitoringReceiver.custom.label',
|
||||
title: 'monitoringReceiver.custom.title',
|
||||
info: 'monitoringReceiver.custom.info',
|
||||
key: 'webhook_configs',
|
||||
logo: require(`~/assets/images/vendor/custom.svg`)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -59,24 +59,27 @@ export default {
|
|||
group: 'prometheus',
|
||||
iconSrc: this.prometheusSrc,
|
||||
label: 'monitoring.overview.linkedList.prometheusPromQl.label',
|
||||
description: 'monitoring.overview.linkedList.prometheusPromQl.description',
|
||||
link: `/k8s/clusters/${ this.currentCluster.id }/api/v1/namespaces/cattle-monitoring-system/services/http:rancher-monitoring-prometheus:9090/proxy/graph`,
|
||||
description:
|
||||
'monitoring.overview.linkedList.prometheusPromQl.description',
|
||||
link: `/k8s/clusters/${ this.currentCluster.id }/api/v1/namespaces/cattle-monitoring-system/services/http:rancher-monitoring-prometheus:9090/proxy/graph`,
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
group: 'prometheus',
|
||||
iconSrc: this.prometheusSrc,
|
||||
label: 'monitoring.overview.linkedList.prometheusRules.label',
|
||||
description: 'monitoring.overview.linkedList.prometheusRules.description',
|
||||
link: `/k8s/clusters/${ this.currentCluster.id }/api/v1/namespaces/cattle-monitoring-system/services/http:rancher-monitoring-prometheus:9090/proxy/rules`,
|
||||
description:
|
||||
'monitoring.overview.linkedList.prometheusRules.description',
|
||||
link: `/k8s/clusters/${ this.currentCluster.id }/api/v1/namespaces/cattle-monitoring-system/services/http:rancher-monitoring-prometheus:9090/proxy/rules`,
|
||||
},
|
||||
{
|
||||
enabled: false,
|
||||
group: 'prometheus',
|
||||
iconSrc: this.prometheusSrc,
|
||||
label: 'monitoring.overview.linkedList.prometheusTargets.label',
|
||||
description: 'monitoring.overview.linkedList.prometheusTargets.description',
|
||||
link: `/k8s/clusters/${ this.currentCluster.id }/api/v1/namespaces/cattle-monitoring-system/services/http:rancher-monitoring-prometheus:9090/proxy/targets`,
|
||||
description:
|
||||
'monitoring.overview.linkedList.prometheusTargets.description',
|
||||
link: `/k8s/clusters/${ this.currentCluster.id }/api/v1/namespaces/cattle-monitoring-system/services/http:rancher-monitoring-prometheus:9090/proxy/targets`,
|
||||
},
|
||||
];
|
||||
|
||||
|
|
@ -87,13 +90,17 @@ export default {
|
|||
async fetchDeps() {
|
||||
const { $store, externalLinks } = this;
|
||||
|
||||
const workloads = await Promise.all(Object.values(WORKLOAD_TYPES).map(type => this.$store.dispatch('cluster/findAll', { type })));
|
||||
const workloads = await Promise.all(
|
||||
Object.values(WORKLOAD_TYPES).map(type => this.$store.dispatch('cluster/findAll', { type })
|
||||
)
|
||||
);
|
||||
|
||||
workloads.flat().forEach((workload) => {
|
||||
if (
|
||||
!isEmpty(workload?.spec?.template?.spec?.containers) &&
|
||||
(workload.spec.template.spec.containers.find(c => c.image.includes('quay.io/coreos/prometheus-operator') ||
|
||||
c.image.includes('rancher/coreos-prometheus-operator'))
|
||||
workload.spec.template.spec.containers.find(
|
||||
c => c.image.includes('quay.io/coreos/prometheus-operator') ||
|
||||
c.image.includes('rancher/coreos-prometheus-operator')
|
||||
) &&
|
||||
workload?.metadata?.namespace !== CATTLE_MONITORING_NAMESPACE
|
||||
) {
|
||||
|
|
@ -108,10 +115,24 @@ export default {
|
|||
if (!isEmpty(hash.endpoints)) {
|
||||
const amMatch = findBy(externalLinks, 'group', 'alertmanager');
|
||||
const grafanaMatch = findBy(externalLinks, 'group', 'grafana');
|
||||
const promeMatch = externalLinks.filter(el => el.group === 'prometheus');
|
||||
const alertmanager = findBy(hash.endpoints, 'id', `${ CATTLE_MONITORING_NAMESPACE }/rancher-monitoring-alertmanager`);
|
||||
const grafana = findBy(hash.endpoints, 'id', `${ CATTLE_MONITORING_NAMESPACE }/rancher-monitoring-grafana`);
|
||||
const prometheus = findBy(hash.endpoints, 'id', `${ CATTLE_MONITORING_NAMESPACE }/rancher-monitoring-prometheus`);
|
||||
const promeMatch = externalLinks.filter(
|
||||
el => el.group === 'prometheus'
|
||||
);
|
||||
const alertmanager = findBy(
|
||||
hash.endpoints,
|
||||
'id',
|
||||
`${ CATTLE_MONITORING_NAMESPACE }/rancher-monitoring-alertmanager`
|
||||
);
|
||||
const grafana = findBy(
|
||||
hash.endpoints,
|
||||
'id',
|
||||
`${ CATTLE_MONITORING_NAMESPACE }/rancher-monitoring-grafana`
|
||||
);
|
||||
const prometheus = findBy(
|
||||
hash.endpoints,
|
||||
'id',
|
||||
`${ CATTLE_MONITORING_NAMESPACE }/rancher-monitoring-prometheus`
|
||||
);
|
||||
|
||||
if (!isEmpty(alertmanager) && !isEmpty(alertmanager.subsets)) {
|
||||
amMatch.enabled = true;
|
||||
|
|
@ -126,7 +147,7 @@ export default {
|
|||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
@ -142,112 +163,48 @@ export default {
|
|||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div class="links">
|
||||
<div>
|
||||
<Banner v-if="v1Installed" color="warning">
|
||||
<template #default>
|
||||
<t k="monitoring.v1Warning" :raw="true" />
|
||||
</template>
|
||||
</Banner>
|
||||
<div v-for="fel in externalLinks" :key="fel.label" class="link-container">
|
||||
<a v-if="fel.enabled" :href="fel.link" target="_blank" rel="noopener noreferrer">
|
||||
<div class="link-logo">
|
||||
<LazyImage :src="fel.iconSrc" />
|
||||
</div>
|
||||
<div class="link-content">
|
||||
<t :k="fel.label" />
|
||||
<i class="icon icon-external-link pull-right" />
|
||||
<hr />
|
||||
<div class="description"><t :k="fel.description" /></div>
|
||||
</div>
|
||||
</a>
|
||||
<a v-else v-tooltip="t('monitoring.overview.linkedList.na')" href="javascript:void(0)" :disabled="!fel.enabled">
|
||||
<div class="link-logo">
|
||||
<LazyImage :src="fel.iconSrc" />
|
||||
</div>
|
||||
<div class="link-content">
|
||||
<t :k="fel.label" />
|
||||
<i class="icon icon-external-link pull-right" />
|
||||
<hr />
|
||||
<div class="description"><t :k="fel.description" /></div>
|
||||
</div>
|
||||
</a>
|
||||
<div class="create-resource-container">
|
||||
<div class="subtypes-container">
|
||||
<a
|
||||
v-for="fel in externalLinks"
|
||||
:key="fel.label"
|
||||
v-tooltip="!fel.enabled ? t('monitoring.overview.linkedList.na') : undefined"
|
||||
:href="fel.enabled ? fel.link : (void 0)"
|
||||
:disabled="!fel.enabled"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
:class="{ 'subtype-banner': true, disabled: !fel.enabled}"
|
||||
>
|
||||
<div class="subtype-content">
|
||||
<div class="title">
|
||||
<div class="subtype-logo round-image">
|
||||
<LazyImage :src="fel.iconSrc" />
|
||||
</div>
|
||||
<h5>
|
||||
<span>
|
||||
<t :k="fel.label" />
|
||||
</span>
|
||||
</h5>
|
||||
<div class="flex-right">
|
||||
<i class="icon icon-external-link" />
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="description">
|
||||
<span>
|
||||
<t :k="fel.description" />
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.links {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
width: 100%;
|
||||
|
||||
.link-container {
|
||||
background-color: var(--input-bg);
|
||||
border-radius: var(--border-radius);
|
||||
border: solid 1px var(--input-border);
|
||||
display: flex;
|
||||
flex-basis: 40%;
|
||||
margin: 0 10px 10px 0;
|
||||
max-width: 325px;
|
||||
min-height: 100px;
|
||||
border-left: solid 10px var(--primary);
|
||||
|
||||
a[disabled] {
|
||||
cursor: not-allowed;
|
||||
background-color: var(---disabled-bg);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0px 0px 1px var(--outline-width) var(--outline);
|
||||
}
|
||||
|
||||
> a {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex: 1 0;
|
||||
padding: 10px;
|
||||
|
||||
.link-logo,
|
||||
.link-content {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.link-logo {
|
||||
text-align: center;
|
||||
// position: absolute;
|
||||
// left: 25px;
|
||||
// top: 25px;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: calc(2 * var(--border-radius));
|
||||
background-color: white;
|
||||
|
||||
img {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
-o-object-fit: contain;
|
||||
object-fit: contain;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.link-content {
|
||||
width: 100%;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.description {
|
||||
margin-top: 10px;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 3;
|
||||
line-clamp: 3;
|
||||
text-overflow: ellipsis;
|
||||
color: var(--secondary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Reference in New Issue