Added AND/OR toggle to alerts.
This commit is contained in:
parent
238dce78b5
commit
0369446681
|
@ -1,6 +1,7 @@
|
|||
<template>
|
||||
<router-link
|
||||
<RouterLink
|
||||
:to="`/actor/${actor.id}/${actor.slug}`"
|
||||
:target="target"
|
||||
class="actor nolink"
|
||||
>
|
||||
<div class="avatar">
|
||||
|
@ -18,7 +19,7 @@
|
|||
</div>
|
||||
|
||||
<span class="name">{{ actor.name }}</span>
|
||||
</router-link>
|
||||
</RouterLink>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -36,6 +37,10 @@ export default {
|
|||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
target: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
unstashActor,
|
||||
|
|
|
@ -14,7 +14,17 @@
|
|||
>
|
||||
<div class="dialog-section">
|
||||
<h3 class="dialog-heading">
|
||||
When<span class="dialog-description">All to appear in the same scene</span>
|
||||
When
|
||||
|
||||
<label class="dialog-description noselect">
|
||||
<template v-if="all">Scene must match <strong>all</strong> fields</template>
|
||||
<template v-else>Scene must match <strong>any</strong> field</template>
|
||||
|
||||
<Toggle
|
||||
:checked="all"
|
||||
@change="(checked) => all = checked"
|
||||
/>
|
||||
</label>
|
||||
</h3>
|
||||
|
||||
<div class="alert-section">
|
||||
|
@ -34,7 +44,10 @@
|
|||
:key="`actor-${actor.id}`"
|
||||
class="actor"
|
||||
>
|
||||
<ActorPreview :actor="actor" />
|
||||
<ActorPreview
|
||||
:actor="actor"
|
||||
target="_blank"
|
||||
/>
|
||||
|
||||
<Icon
|
||||
icon="cross3"
|
||||
|
@ -109,10 +122,15 @@
|
|||
|
||||
<div class="entities">
|
||||
<div
|
||||
v-if="entity"
|
||||
v-for="(entity, index) in entities"
|
||||
:key="`entity-${entity.id}`"
|
||||
:class="{ invalid: all && index > 0 }"
|
||||
class="entity"
|
||||
>
|
||||
<Entity :entity="entity" />
|
||||
<Entity
|
||||
:entity="entity"
|
||||
target="_blank"
|
||||
/>
|
||||
|
||||
<Icon
|
||||
icon="cross3"
|
||||
|
@ -121,7 +139,7 @@
|
|||
/>
|
||||
</div>
|
||||
|
||||
<Tooltip v-if="!entity">
|
||||
<Tooltip v-if="entities.length < 1 || !all">
|
||||
<div class="entity placeholder">
|
||||
Any channel
|
||||
|
||||
|
@ -278,6 +296,7 @@
|
|||
import ActorPreview from '../actors/preview.vue';
|
||||
import Entity from '../entities/tile.vue';
|
||||
import Checkbox from '../form/checkbox.vue';
|
||||
import Toggle from '../form/toggle.vue';
|
||||
import Search from './search.vue';
|
||||
|
||||
async function addAlert() {
|
||||
|
@ -285,10 +304,11 @@ async function addAlert() {
|
|||
|
||||
try {
|
||||
await this.$store.dispatch('addAlert', {
|
||||
all: this.all,
|
||||
actors: this.actors.map((actor) => actor.id),
|
||||
tags: this.tags.map((tag) => tag.id),
|
||||
matches: this.matches,
|
||||
entity: this.entity?.id,
|
||||
entities: this.entities.map((entity) => entity.id),
|
||||
notify: this.notify,
|
||||
email: this.email,
|
||||
stashes: this.stashes.map((stash) => stash.id),
|
||||
|
@ -309,7 +329,7 @@ function addActor(actor) {
|
|||
}
|
||||
|
||||
function addEntity(entity) {
|
||||
this.entity = entity;
|
||||
this.entities = this.entities.concat(entity);
|
||||
this.events.emit('blur');
|
||||
}
|
||||
|
||||
|
@ -325,8 +345,8 @@ function removeActor(actor) {
|
|||
this.actors = this.actors.filter((listedActor) => listedActor.id !== actor.id);
|
||||
}
|
||||
|
||||
function removeEntity() {
|
||||
this.entity = null;
|
||||
function removeEntity(entity) {
|
||||
this.entities = this.entities.filter((alertEntity) => alertEntity.id !== entity.id);
|
||||
}
|
||||
|
||||
function removeTag(tag) {
|
||||
|
@ -371,6 +391,7 @@ export default {
|
|||
Checkbox,
|
||||
Entity,
|
||||
Search,
|
||||
Toggle,
|
||||
},
|
||||
emits: ['close'],
|
||||
data() {
|
||||
|
@ -378,7 +399,8 @@ export default {
|
|||
error: null,
|
||||
actors: [],
|
||||
tags: [],
|
||||
entity: null,
|
||||
all: true,
|
||||
entities: [],
|
||||
matches: [],
|
||||
matchProperty: 'title',
|
||||
matchExpression: null,
|
||||
|
@ -424,9 +446,15 @@ export default {
|
|||
}
|
||||
|
||||
.dialog-description {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--shadow);
|
||||
font-size: .9rem;
|
||||
font-weight: normal;
|
||||
|
||||
.toggle-container {
|
||||
margin-left: .5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.dialog-error {
|
||||
|
@ -488,6 +516,11 @@ export default {
|
|||
margin: 0 .5rem .5rem 0;
|
||||
}
|
||||
|
||||
.entity.invalid {
|
||||
opacity: .5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.entity .tile {
|
||||
width: 10rem;
|
||||
height: 2.5rem;
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
<template>
|
||||
<router-link
|
||||
<RouterLink
|
||||
:to="`/${entity.type}/${entity.slug}`"
|
||||
:title="entity.name"
|
||||
:target="target"
|
||||
class="tile"
|
||||
>
|
||||
<div class="tile-logo">
|
||||
|
@ -47,7 +48,7 @@
|
|||
<span v-if="typeof entity.sceneTotal !== 'undefined'">{{ entity.sceneTotal }} scenes</span>
|
||||
<span v-if="entity.type === 'network'">{{ entity.childrenTotal }} channels</span>
|
||||
</span>
|
||||
</router-link>
|
||||
</RouterLink>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -57,6 +58,10 @@ export default {
|
|||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
target: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
emits: ['load'],
|
||||
};
|
||||
|
|
|
@ -99,7 +99,7 @@
|
|||
|
||||
<Icon
|
||||
v-if="notification.alert"
|
||||
v-tooltip="`You set an alert for <strong>${notification.alert.tags.map(tag => tag.name).join(', ') || 'all'}</strong> scenes with <strong>${notification.alert.actors.map(actor => actor.name).join(', ') || 'any actor'}</strong> from <strong>${notification.alert.entities.map((entity) => entity.name).join(', ') || 'any channel'}</strong> matching <strong>${notification.alert.matches.map((match) => `${match.property}: ${match.expression}`).join(', ') || 'anything'}</strong>`"
|
||||
v-tooltip="`You set an alert for scenes with <strong>${notification.alert.all ? 'all of' : 'any of'}</strong> <strong>${notification.alert.actors.map(actor => actor.name).join(', ') || 'any actor'}</strong> containing <strong>${notification.alert.tags.map(tag => tag.name).join(', ') || 'any tags'}</strong> from <strong>${notification.alert.entities.map((entity) => entity.name).join(', ') || 'any channel'}</strong> matching <strong>${notification.alert.matches.map((match) => `${match.property}: ${match.expression}`).join(', ') || 'any text'}</strong>`"
|
||||
icon="question5"
|
||||
@click.prevent.stop
|
||||
/>
|
||||
|
|
|
@ -68,6 +68,7 @@ function initUiActions(store, _router) {
|
|||
${releaseFields}
|
||||
}
|
||||
alert {
|
||||
all
|
||||
tags: alertsTags {
|
||||
tag {
|
||||
id
|
||||
|
|
|
@ -71,6 +71,7 @@ function initUsersActions(store, _router) {
|
|||
id
|
||||
notify
|
||||
email
|
||||
all
|
||||
stashes: alertsStashes {
|
||||
stash {
|
||||
id
|
||||
|
|
|
@ -34,5 +34,9 @@ exports.down = async (knex) => {
|
|||
table.dropColumn('all');
|
||||
});
|
||||
|
||||
await knex.schema.alterTable('alerts_entities', (table) => {
|
||||
table.unique('alert_id');
|
||||
});
|
||||
|
||||
await knex.schema.dropTable('alerts_matches');
|
||||
};
|
||||
|
|
|
@ -24,6 +24,7 @@ async function addAlert(alert, sessionUser) {
|
|||
user_id: sessionUser.id,
|
||||
notify: alert.notify,
|
||||
email: alert.email,
|
||||
all: alert.all,
|
||||
})
|
||||
.returning('id');
|
||||
|
||||
|
@ -45,10 +46,10 @@ async function addAlert(alert, sessionUser) {
|
|||
alert_id: alertId,
|
||||
stash_id: stashId,
|
||||
})), false),
|
||||
alert.entity && bulkInsert('alerts_entities', [{
|
||||
alert.entities && bulkInsert('alerts_entities', alert.entities.map((entityId) => ({
|
||||
alert_id: alertId,
|
||||
entity_id: alert.entity,
|
||||
}], false),
|
||||
entity_id: entityId,
|
||||
})).slice(0, alert.all ? 1 : Infinity), false), // one scene can never match multiple entities in AND mode
|
||||
]);
|
||||
|
||||
return alertId;
|
||||
|
@ -121,8 +122,6 @@ async function notify(scenes) {
|
|||
return acc;
|
||||
}, {});
|
||||
|
||||
console.log(alertsStashesByAlertId);
|
||||
|
||||
const alerts = rawAlerts.map((alert) => ({
|
||||
id: alert.id,
|
||||
userId: alert.user_id,
|
||||
|
@ -148,32 +147,45 @@ async function notify(scenes) {
|
|||
|
||||
const triggers = alerts.flatMap((alert) => {
|
||||
const alertScenes = curatedScenes.filter((scene) => {
|
||||
console.log(scene.title, alert.tags, scene.tagIds);
|
||||
|
||||
if (alert.all) {
|
||||
if (alert.actors.length > 0 && !alert.actors.every((actorId) => scene.actorIds.includes(actorId))) {
|
||||
console.log('THROW ACTORS');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (alert.tags.length > 0 && !alert.tags.every((tagId) => scene.tagIds.includes(tagId))) {
|
||||
console.log('THROW TAGS');
|
||||
return false;
|
||||
}
|
||||
|
||||
// multiple entities can only be matched in OR mode
|
||||
if (alert.entities.length > 0 && !alert.entities.some((alertEntityId) => alertEntityId === scene.entityId || alertEntityId === scene.parentEntityId)) {
|
||||
console.log('THROW ENTITIES');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (alert.matches.length > 0 && !alert.matches.every((match) => match.expression.test(scene[match.property]))) {
|
||||
console.log('THROW MATCHES');
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log('OK');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (alert.actors.some((actorId) => scene.actorIds.includes(actorId))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (alert.tags.some((tagId) => scene.tagIds.includes(tagId))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// multiple entities can only be matched in OR mode
|
||||
if (alert.entities.some((alertEntityId) => alertEntityId === scene.entityId || alertEntityId === scene.parentEntityId)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (alert.matches.some((match) => match.expression.test(scene[match.property]))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
return alertScenes.map((scene) => ({
|
||||
|
@ -191,15 +203,11 @@ async function notify(scenes) {
|
|||
scene_id: trigger.sceneId,
|
||||
}));
|
||||
|
||||
console.log('triggers', triggers);
|
||||
|
||||
const stashes = Object.values(Object.fromEntries(triggers.flatMap((trigger) => trigger.alert.stashes.map((stashId) => ({
|
||||
scene_id: trigger.sceneId,
|
||||
stash_id: stashId,
|
||||
}))).map((stash) => [`${stash.stash_id}:${stash.scene_id}`, stash])));
|
||||
|
||||
console.log('stashes', stashes);
|
||||
|
||||
await Promise.all([
|
||||
bulkInsert('notifications', notifications, false),
|
||||
bulkInsert('stashes_scenes', stashes, false),
|
||||
|
|
Loading…
Reference in New Issue