Feature/event notifications (#399)

* additional server events

* sort 'recent recipes' by updated

* remove duplicate code

* fixes #396

* set color

* consolidate tag/category pages

* set colors

* list unorganized recipes

* cleanup old code

* remove flash message, switch to global snackbar

* cancel to close

* cleanup

* notifications first pass

* test notification

* complete notification feature

* use background tasks

* add url param

* update documentation

Co-authored-by: hay-kot <hay-kot@pm.me>
This commit is contained in:
Hayden
2021-05-08 18:29:31 -08:00
committed by GitHub
parent 8923c1ecf8
commit 14b6ab7ec7
49 changed files with 875 additions and 355 deletions

View File

@@ -1,6 +1,6 @@
<template>
<div>
<base-dialog
<BaseDialog
ref="assignDialog"
title-icon="mdi-tag"
color="primary"
@@ -33,7 +33,7 @@
:single-column="true"
/>
</template>
</base-dialog>
</BaseDialog>
<v-btn @click="openDialog" small color="success">
{{ $t("settings.toolbox.bulk-assign") }}

View File

@@ -0,0 +1,236 @@
<template>
<div>
<v-card outlined class="mt-n1">
<v-card-actions>
<v-spacer></v-spacer>
<BaseDialog
:keep-open="keepDialogOpen"
title-icon="mdi-bell-alert"
:title="$t('general.new') + ' ' + $t('events.notification')"
@submit="createNotification"
>
<template v-slot:open="{ open }">
<v-btn small color="info" @click="open">
<v-icon left>
mdi-plus
</v-icon>
{{ $t("events.notification") }}
</v-btn>
</template>
<template v-slot:default>
<v-card-text class="mt-2">
{{ $t("events.new-notification-form-description") }}
<div class="d-flex justify-space-around mt-1 mb-3">
<a href="https://github.com/caronc/apprise/wiki" target="_blanks"> Apprise </a>
<a href="https://github.com/caronc/apprise/wiki/Notify_gotify" target="_blanks"> Gotify </a>
<a href="https://github.com/caronc/apprise/wiki/Notify_discord" target="_blanks"> Discord </a>
<a href="https://github.com/caronc/apprise/wiki/Notify_homeassistant" target="_blanks">
Home Assistant
</a>
<a href="https://github.com/caronc/apprise/wiki/Notify_matrix" target="_blanks"> Matrix </a>
<a href="https://github.com/caronc/apprise/wiki/Notify_pushover" target="_blanks"> Pushover </a>
</div>
<v-form ref="notificationForm">
<v-select
:label="$t('general.type')"
:rules="[existsRule]"
:items="notificationTypes"
item-value="text"
v-model="newNotification.type"
>
</v-select>
<v-text-field :rules="[existsRule]" :label="$t('general.name')" v-model="newNotification.name">
</v-text-field>
<v-text-field
required
:rules="[existsRule]"
:label="$t('events.apprise-url')"
v-model="newNotification.notificationUrl"
>
</v-text-field>
<v-btn class="d-flex ml-auto" small color="info" @click="testByURL(newNotification.notificationUrl)">
<v-icon left> mdi-test-tube</v-icon>
{{ $t("general.test") }}
</v-btn>
<v-subheader class="pa-0 mb-0">
{{ $t("events.subscribed-events") }}
</v-subheader>
<v-row class="mt-1">
<v-col cols="3" v-for="(item, key, index) in newNotificationOptions" :key="index">
<v-checkbox class="my-n3 py-0" v-model="newNotificationOptions[key]" :label="key"> </v-checkbox>
</v-col>
</v-row>
</v-form>
</v-card-text>
</template>
</BaseDialog>
</v-card-actions>
<v-simple-table>
<template v-slot:default>
<thead>
<tr>
<th class="text-center">
{{ $t("general.type") }}
</th>
<th class="text-center">
{{ $t("general.name") }}
</th>
<th class="text-center">
{{ $t("general.general") }}
</th>
<th class="text-center">
{{ $t("general.recipe") }}
</th>
<th class="text-center">
{{ $t("events.database") }}
</th>
<th class="text-center">
{{ $t("events.scheduled") }}
</th>
<th class="text-center">
{{ $t("settings.migrations") }}
</th>
<th class="text-center">
{{ $t("group.group") }}
</th>
<th class="text-center">
{{ $t("user.user") }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in notifications" :key="index">
<td>
<v-avatar size="35" class="ma-1" :color="getIcon(item.type).icon ? 'primary' : undefined">
<v-icon dark v-if="getIcon(item.type).icon"> {{ getIcon(item.type).icon }}</v-icon>
<v-img v-else :src="getIcon(item.type).image"> </v-img>
</v-avatar>
{{ item.type }}
</td>
<td>
{{ item.name }}
</td>
<td class="text-center">
<v-icon color="success"> {{ item.general ? "mdi-check" : "" }} </v-icon>
</td>
<td class="text-center">
<v-icon color="success"> {{ item.recipe ? "mdi-check" : "" }} </v-icon>
</td>
<td class="text-center">
<v-icon color="success"> {{ item.backup ? "mdi-check" : "" }} </v-icon>
</td>
<td class="text-center">
<v-icon color="success"> {{ item.scheduled ? "mdi-check" : "" }} </v-icon>
</td>
<td class="text-center">
<v-icon color="success"> {{ item.migration ? "mdi-check" : "" }} </v-icon>
</td>
<td class="text-center">
<v-icon color="success"> {{ item.group ? "mdi-check" : "" }} </v-icon>
</td>
<td class="text-center">
<v-icon color="success"> {{ item.user ? "mdi-check" : "" }} </v-icon>
</td>
<td>
<v-btn class="mx-1" small color="error" @click="deleteNotification(item.id)">
<v-icon> mdi-delete </v-icon>
{{ $t("general.delete") }}
</v-btn>
<v-btn small color="info" @click="testByID(item.id)">
<v-icon left> mdi-test-tube</v-icon>
{{ $t("general.test") }}
</v-btn>
</td>
</tr>
</tbody>
</template>
</v-simple-table>
</v-card>
</div>
</template>
<script>
import BaseDialog from "@/components/UI/Dialogs/BaseDialog";
import { api } from "@/api";
import { validators } from "@/mixins/validators";
export default {
components: {
BaseDialog,
},
mixins: [validators],
data() {
return {
keepDialogOpen: false,
notifications: [],
newNotification: {
type: "General",
name: "",
notificationUrl: "",
},
newNotificationOptions: {
general: true,
recipe: true,
backup: true,
scheduled: true,
migration: true,
group: true,
user: true,
},
notificationTypes: [
{
text: "General",
icon: "mdi-bell-alert",
},
{
text: "Discord",
image: "./static/discord.svg",
},
{
text: "Gotify",
image: "./static/gotify.png",
},
{
text: "Home Assistant",
image: "./static/home-assistant.png",
},
{
text: "Pushover",
image: "./static/pushover.svg",
},
],
};
},
mounted() {
this.getAllNotifications();
},
methods: {
getIcon(textValue) {
return this.notificationTypes.find(x => x.text === textValue);
},
async getAllNotifications() {
this.notifications = await api.about.allEventNotifications();
},
async createNotification() {
if (this.$refs.notificationForm.validate()) {
this.keepDialogOpen = false;
await api.about.createNotification({ ...this.newNotification, ...this.newNotificationOptions });
this.getAllNotifications();
} else {
this.keepDialogOpen = true;
}
},
async deleteNotification(id) {
await api.about.deleteNotification(id);
this.getAllNotifications();
},
async testByID(id) {
await api.about.testNotificationByID(id);
},
async testByURL(url) {
await api.about.testNotificationByURL(url);
},
},
};
</script>

View File

@@ -4,6 +4,10 @@
<v-tabs v-model="tab" background-color="primary" centered dark icons-and-text>
<v-tabs-slider></v-tabs-slider>
<v-tab href="#event-notifications">
Notify
<v-icon>mdi-bell-alert</v-icon>
</v-tab>
<v-tab href="#category-editor">
{{ $t("recipe.categories") }}
<v-icon>mdi-tag-multiple-outline</v-icon>
@@ -20,20 +24,23 @@
</v-tabs>
<v-tabs-items v-model="tab">
<v-tab-item value="event-notifications"> <EventNotification /></v-tab-item>
<v-tab-item value="category-editor"> <CategoryTagEditor :is-tags="false"/></v-tab-item>
<v-tab-item value="tag-editor"> <CategoryTagEditor :is-tags="true" /> </v-tab-item>
<v-tab-item value="organize"> <RecipeOrganizer :is-tags="true" /> </v-tab-item>
<v-tab-item value="organize"> <RecipeOrganizer /> </v-tab-item>
</v-tabs-items>
</v-card>
</div>
</template>
<script>
import EventNotification from "./EventNotification";
import CategoryTagEditor from "./CategoryTagEditor";
import RecipeOrganizer from "./RecipeOrganizer";
export default {
components: {
CategoryTagEditor,
EventNotification,
RecipeOrganizer,
},
computed: {