alerta_alerta-webui/src/components/BlackoutList.vue

773 lines
21 KiB
Vue

<template>
<div>
<v-dialog
v-model="dialog"
max-width="540px"
>
<v-form ref="form">
<v-card>
<v-card-title>
<span class="headline">
{{ formTitle }}
</span>
</v-card-title>
<v-card-text>
<v-container grid-list-md>
<v-layout wrap>
<v-flex
v-if="$config.customer_views"
xs12
>
<v-select
v-model="editedItem.customer"
:items="allowedCustomers"
:label="$t('Customer')"
clearable
/>
</v-flex>
<v-flex
xs12
>
<v-select
v-model="editedItem.environment"
:items="allowedEnvironments"
:label="$t('Environment')"
:rules="[rules.required]"
required
/>
</v-flex>
<v-flex
xs4
>
<v-menu
ref="menu1"
v-model="menu1"
:close-on-content-click="false"
:nudge-right="40"
lazy
transition="scale-transition"
offset-y
full-width
max-width="290px"
min-width="290px"
>
<v-text-field
slot="activator"
v-model="editedItem.period.startDate"
:label="$t('StartDate')"
prepend-icon="event"
/>
<v-date-picker
v-model="editedItem.period.startDate"
no-title
@input="menu1 = false"
/>
</v-menu>
</v-flex>
<v-flex
xs2
>
<v-combobox
v-model="editedItem.period.startTime"
:items="times"
/>
</v-flex>
<v-flex
xs2
>
<v-combobox
v-model="editedItem.period.endTime"
:items="times"
/>
</v-flex>
<v-flex
xs4
>
<v-menu
v-model="menu2"
:close-on-content-click="false"
:nudge-right="40"
lazy
transition="scale-transition"
offset-y
full-width
max-width="290px"
min-width="290px"
>
<v-text-field
slot="activator"
v-model="editedItem.period.endDate"
:label="$t('EndDate')"
/>
<v-date-picker
v-model="editedItem.period.endDate"
no-title
@input="menu2 = false"
/>
</v-menu>
</v-flex>
<v-flex
xs12
>
<v-combobox
v-model="editedItem.service"
:items="currentServices"
:menu-props="{ maxHeight: '400' }"
:label="$t('Service')"
chips
multiple
:hint="$t('ChooseService')"
persistent-hint
/>
</v-flex>
<v-flex
xs12
>
<v-text-field
v-model.trim="editedItem.resource"
:label="$t('Resource')"
/>
</v-flex>
<v-flex
xs12
>
<v-text-field
v-model.trim="editedItem.event"
:label="$t('Event')"
/>
</v-flex>
<v-flex
xs12
>
<v-text-field
v-model.trim="editedItem.group"
:label="$t('Group')"
/>
</v-flex>
<v-flex
xs12
>
<v-combobox
v-model="editedItem.tags"
:items="currentTags"
:label="$t('Tags')"
multiple
chips
>
<template
slot="selection"
slot-scope="data"
>
<v-chip
:key="JSON.stringify(data.item)"
:selected="data.selected"
:disabled="data.disabled"
class="v-chip--select-multi"
label
small
@input="data.parent.selectItem(data.item)"
>
<v-icon left>
label
</v-icon>{{ data.item }}
</v-chip>
</template>
</v-combobox>
</v-flex>
<v-flex
xs12
>
<v-text-field
v-model.trim="editedItem.origin"
:label="$t('Origin')"
/>
</v-flex>
<v-flex
xs12
>
<v-text-field
v-model.trim="editedItem.text"
:label="$t('Reason')"
/>
</v-flex>
</v-layout>
</v-container>
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn
color="blue darken-1"
flat
@click="close"
>
{{ $t('Cancel') }}
</v-btn>
<v-btn
color="blue darken-1"
flat
@click="validate"
>
{{ $t('Save') }}
</v-btn>
</v-card-actions>
</v-card>
</v-form>
</v-dialog>
<v-card>
<v-card-title class="title">
{{ $t('Blackouts') }}
<v-spacer />
<v-btn-toggle
v-model="status"
class="transparent"
multiple
>
<v-btn
value="active"
flat
>
<v-tooltip bottom>
<v-icon slot="activator">
notifications_paused
</v-icon>
<span>{{ $t('Active') }}</span>
</v-tooltip>
</v-btn>
<v-btn
value="pending"
flat
>
<v-tooltip bottom>
<v-icon slot="activator">
schedule
</v-icon>
<span>{{ $t('Pending') }}</span>
</v-tooltip>
</v-btn>
<v-btn
value="expired"
flat
>
<v-tooltip bottom>
<v-icon slot="activator">
block
</v-icon>
<span>{{ $t('Expired') }}</span>
</v-tooltip>
</v-btn>
</v-btn-toggle>
<v-spacer />
<v-text-field
v-model="search"
append-icon="search"
:label="$t('Search')"
single-line
hide-details
/>
</v-card-title>
<v-data-table
:headers="computedHeaders"
:items="blackouts"
:rows-per-page-items="rowsPerPageItems"
:pagination.sync="pagination"
class="px-2"
:search="search"
:loading="isLoading"
must-sort
sort-icon="arrow_drop_down"
>
<template
slot="items"
slot-scope="props"
>
<td>
<v-tooltip top>
{{ $t('WholeEnvironment') }}
<v-icon
v-if="onlyEnvironment(props.item)"
slot="activator"
color="red"
small
>
report_problem
</v-icon>
</v-tooltip>
<v-tooltip top>
{{ $t('AllOrigin') }}
<v-icon
v-if="onlyOrigin(props.item)"
slot="activator"
color="red"
small
>
report_problem
</v-icon>
</v-tooltip>
</td>
<td
v-if="$config.customer_views"
>
{{ props.item.customer }}
</td>
<td>{{ props.item.environment }}</td>
<td>
<v-chip
v-for="service in props.item.service"
:key="service"
outline
small
>
{{ service }}
</v-chip>
</td>
<td>{{ props.item.resource }}</td>
<td>{{ props.item.event }}</td>
<td>{{ props.item.group }}</td>
<td>
<v-chip
v-for="tag in props.item.tags"
:key="tag"
label
small
>
<v-icon left>
label
</v-icon>{{ tag }}
</v-chip>
</td>
<td>{{ props.item.origin }}</td>
<td class="text-xs-right">
<v-tooltip top>
{{ props.item.status | capitalize }}
<v-icon
v-if="props.item.status == 'pending'"
slot="activator"
light
small
>
schedule
</v-icon>
<v-icon
v-if="props.item.status == 'active'"
slot="activator"
color="primary"
small
>
notifications_paused
</v-icon>
<v-icon
v-if="props.item.status == 'expired'"
slot="activator"
small
>
block
</v-icon>
</v-tooltip>
</td>
<td class="text-xs-left">
<date-time
:value="props.item.startTime"
format="mediumDate"
/>
</td>
<td class="text-xs-left">
<date-time
:value="props.item.endTime"
format="mediumDate"
/>
</td>
<td
class="text-xs-left text-no-wrap"
>
{{ props.item.endTime | until }}
</td>
<td class="text-xs-left">
{{ props.item.user }}
</td>
<td class="text-xs-left">
{{ props.item.text }}
</td>
<td class="text-no-wrap">
<v-btn
v-has-perms.disable="'write:blackouts'"
icon
class="btn--plain mr-0"
@click="editItem(props.item)"
>
<v-icon
small
color="grey darken-3"
>
edit
</v-icon>
</v-btn>
<v-btn
v-has-perms.disable="'write:blackouts'"
icon
class="btn--plain mx-0"
@click="copyItem(props.item)"
>
<v-icon
small
color="grey darken-3"
>
content_copy
</v-icon>
</v-btn>
<v-btn
v-has-perms.disable="'write:blackouts'"
icon
class="btn--plain mx-0"
@click="deleteItem(props.item)"
>
<v-icon
small
color="grey darken-3"
>
delete
</v-icon>
</v-btn>
</td>
</template>
<template slot="no-data">
<v-alert
:value="true"
color="error"
icon="warning"
>
{{ $t('NoDisplay') }}
</v-alert>
</template>
<v-alert
slot="no-results"
:value="true"
color="error"
icon="warning"
>
{{ $t('SearchNoResult1') }} "{{ search }}" {{ $t('SearchNoResult2') }}
</v-alert>
</v-data-table>
</v-card>
<list-button-add
perms="write:blackouts"
@add-to-list="dialog = true"
/>
</div>
</template>
<script>
import DateTime from './lib/DateTime'
import ListButtonAdd from './lib/ListButtonAdd'
import moment from 'moment'
import i18n from '@/plugins/i18n'
export default {
components: {
DateTime,
ListButtonAdd
},
data: vm => ({
descending: true,
page: 1,
rowsPerPageItems: [10, 20, 30, 40, 50],
pagination: {
sortBy: 'startTime',
rowsPerPage: 20
},
// totalItems: number,
status: ['active', 'pending', 'expired'],
search: '',
dialog: false,
headers: [
{ text: '', value: 'icons' },
{ text: i18n.t('Customer'), value: 'customer' },
{ text: i18n.t('Environment'), value: 'environment' },
{ text: i18n.t('Service'), value: 'service' },
{ text: i18n.t('Resource'), value: 'resource' },
{ text: i18n.t('Event'), value: 'event' },
{ text: i18n.t('Group'), value: 'group' },
{ text: i18n.t('Tags'), value: 'tags' },
{ text: i18n.t('Origin'), value: 'origin' },
{ text: '', value: 'status' },
{ text: i18n.t('Start'), value: 'startTime' },
{ text: i18n.t('End'), value: 'endTime' },
{ text: i18n.t('Expires'), value: 'remaining' },
{ text: i18n.t('User'), value: 'user' },
// { text: 'Created', value: 'createTime' }, FIXME
{ text: i18n.t('Reason'), value: 'text' },
{ text: i18n.t('Actions'), value: 'name', sortable: false }
],
editedId: null,
editedItem: {
customer: null,
environment: null,
service: [],
resource: null,
event: null,
group: null,
tags: [],
origin: null,
period: {
startDate: null,
startTime: null,
endDate: null,
endTime: null
},
text: ''
},
menu1: false,
menu2: false,
defaultItem: {
customer: null,
environment: null,
service: [],
resource: null,
event: null,
group: null,
tags: [],
origin: null,
period: {
startDate: null,
startTime: null,
endDate: null,
endTime: null
},
text: ''
},
rules: {
required: v => !!v || i18n.t('Required')
}
}),
computed: {
blackouts() {
return this.$store.state.blackouts.blackouts
.filter(b => !this.status || this.status.includes(b.status))
.map(b => {
let s = moment(b.startTime)
let e = moment(b.endTime)
return Object.assign(b, {
period: {
startDate: s.format('YYYY-MM-DD'),
startTime: s.format('HH:mm'),
endDate: e.format('YYYY-MM-DD'),
endTime: e.format('HH:mm')
}
})
})
},
computedHeaders() {
return this.headers.filter(h => !this.$config.customer_views ? h.value != 'customer' : true)
},
allowedCustomers() {
return this.$store.getters['customers/customers']
},
allowedEnvironments() {
return this.$store.getters['alerts/environments']()
},
currentServices() {
return this.$store.getters['alerts/services']
},
currentTags() {
return this.$store.getters['alerts/tags']
},
isLoading() {
return this.$store.state.blackouts.isLoading
},
formTitle() {
return !this.editedId ? i18n.t('NewBlackout') : i18n.t('EditBlackout')
},
blackoutStartNow() {
return this.$store.getters.getPreference('blackoutStartNow')
},
blackoutPeriod() {
return (
(this.$store.getters.getPreference('blackoutPeriod') ||
this.$store.getters.getConfig('blackouts').duration)
)
},
times() {
return Array.from(
{
length: (24 * 60) / 15
},
(v, i) => {
let h = Math.floor((i * 15) / 60)
let m = i * 15 - h * 60
return ('0' + h).slice(-2) + ':' + ('0' + m).slice(-2)
}
)
},
refresh() {
return this.$store.state.refresh
}
},
watch: {
dialog(val) {
val || this.close()
},
refresh(val) {
if (!val) return
this.getBlackouts()
this.getCustomers()
this.getEnvironments()
this.getServices()
this.getTags()
}
},
created() {
this.getBlackouts()
this.getCustomers()
this.getEnvironments()
this.getServices()
this.getTags()
this.editedItem = Object.assign({}, this.defaultItem)
this.editedItem.period = this.defaultTimes()
},
methods: {
getBlackouts() {
this.$store.dispatch('blackouts/getBlackouts')
},
getCustomers() {
this.$store.dispatch('customers/getCustomers')
},
getEnvironments() {
this.$store.dispatch('alerts/getEnvironments')
},
getServices() {
this.$store.dispatch('alerts/getServices')
},
getTags() {
this.$store.dispatch('alerts/getTags')
},
getBlackoutTime(date) {
if (this.blackoutStartNow) {
return moment(date)
}
// return soonest 15 minute interval
return moment(
new Date(
Math.ceil(date.getTime() / 1000 / 60 / 15) * 1000 * 60 * 15
).toISOString()
)
},
defaultTimes() {
let now = new Date()
let start = this.getBlackoutTime(now)
now.setTime(now.getTime() + this.blackoutPeriod * 1000)
let end = this.getBlackoutTime(now)
return {
startDate: start.format('YYYY-MM-DD'),
startTime: start.format('HH:mm'),
endDate: end.format('YYYY-MM-DD'),
endTime: end.format('HH:mm')
}
},
toISODate(date, time) {
return new Date(date + ' ' + time).toISOString()
},
blackoutAttributes(blackout) {
const alertAttr = ['environment', 'service', 'resource', 'event', 'group', 'tags', 'origin']
return Object.entries(blackout)
.filter(([_, v]) => (!Array.isArray(v) && !!v) || (Array.isArray(v) && v.length))
.filter(b => alertAttr.includes(b[0]))
.reduce((a, [k, _]) => a.concat(k), [])
},
onlyEnvironment(blackout) {
return JSON.stringify(this.blackoutAttributes(blackout)) === JSON.stringify(['environment'])
},
onlyOrigin(blackout) {
return JSON.stringify(this.blackoutAttributes(blackout)) === JSON.stringify(['environment', 'origin'])
},
editItem(item) {
this.editedId = item.id
this.editedItem = Object.assign({}, item)
this.dialog = true
},
copyItem(item) {
this.editedItem = Object.assign({}, item)
this.editedItem.period = this.defaultTimes()
this.editedId = null
this.dialog = true
},
deleteItem(item) {
confirm(i18n.t('ConfirmDelete')) &&
this.$store.dispatch('blackouts/deleteBlackout', item.id)
},
close() {
this.dialog = false
setTimeout(() => {
this.$refs.form.resetValidation()
this.editedItem = Object.assign({}, this.defaultItem)
this.editedItem.period = this.defaultTimes()
this.editedId = null
}, 300)
},
validate() {
if (this.$refs.form.validate()) {
this.$refs.form.resetValidation()
this.save()
}
},
save() {
if (this.editedId) {
this.$store.dispatch('blackouts/updateBlackout', [
this.editedId,
{
customer: this.editedItem.customer,
environment: this.editedItem.environment,
service: this.editedItem.service,
resource: this.editedItem.resource ? this.editedItem.resource : null,
event: this.editedItem.event ? this.editedItem.event : null,
group: this.editedItem.group ? this.editedItem.group : null,
tags: this.editedItem.tags,
origin: this.editedItem.origin ? this.editedItem.origin : null,
startTime: this.toISODate(
this.editedItem.period.startDate,
this.editedItem.period.startTime
),
endTime: this.toISODate(
this.editedItem.period.endDate,
this.editedItem.period.endTime
),
text: this.editedItem.text
}
])
} else {
this.$store.dispatch(
'blackouts/createBlackout',
Object.assign(this.editedItem, {
id: null,
startTime: this.toISODate(
this.editedItem.period.startDate,
this.editedItem.period.startTime
),
endTime: this.toISODate(
this.editedItem.period.endDate,
this.editedItem.period.endTime
)
})
)
}
this.close()
}
}
}
</script>
<style></style>