Refactored alerts to use application code, added regex. Updated Jules Jordan for the Ass Factory relaunch.

This commit is contained in:
DebaucheryLibrarian
2023-11-24 01:29:22 +01:00
parent 124ff3f5e3
commit 238dce78b5
79 changed files with 466 additions and 155 deletions

View File

@@ -3,6 +3,11 @@
title="Add alert"
@close="$emit('close')"
>
<div
v-if="error"
class="dialog-error"
>{{ error }}</div>
<form
class="dialog-body"
@submit.prevent="addAlert"
@@ -136,6 +141,72 @@
</Tooltip>
</div>
</div>
<div class="alert-section">
<h4 class="alert-heading">Matching</h4>
<ul class="matches nolist">
<li
v-for="(match, index) in matches"
:key="`match-${index}`"
class="match"
>
<span class="match-property">{{ match.property }}:&nbsp;</span>
<span
v-if="match.expression.slice(0, 1) === '/' && match.expression.slice(-1) === '/'"
class="match-expression"
><span class="match-slash">/</span>{{ match.expression.slice(1, -1) }}<span class="match-slash">/</span></span>
<span
v-else
class="match-expression"
>{{ match.expression }}</span>
<Icon
icon="cross3"
class="remove"
@click.native="removeMatch(index)"
/>
</li>
<Tooltip
v-if="!entity"
@open="$refs.expression?.focus()"
>
<li class="match placeholder">
Anything
<Icon
icon="plus3"
class="add"
/>
</li>
<template #tooltip>
<form
class="pattern-tooltip"
@submit.prevent="addMatch"
>
<select
v-model="matchProperty"
class="input"
>
<option value="title">Title</option>
<option value="description">Description</option>
</select>
<input
ref="expression"
v-model="matchExpression"
class="input"
placeholder="Expression, // for RegExp"
>
</form>
</template>
</Tooltip>
</ul>
</div>
</div>
<div class="dialog-section">
@@ -194,7 +265,7 @@
<div class="dialog-actions right">
<button
:disabled="actors.length === 0 && tags.length === 0 && !entity"
:disabled="actors.length === 0 && tags.length === 0 && !entity && matches.length === 0"
type="submit"
class="button button-primary"
>Add alert</button>
@@ -210,16 +281,23 @@ import Checkbox from '../form/checkbox.vue';
import Search from './search.vue';
async function addAlert() {
await this.$store.dispatch('addAlert', {
actors: this.actors.map((actor) => actor.id),
tags: this.tags.map((tag) => tag.id),
entity: this.entity?.id,
notify: this.notify,
email: this.email,
stashes: this.stashes.map((stash) => stash.id),
});
this.error = null;
this.$emit('close', true);
try {
await this.$store.dispatch('addAlert', {
actors: this.actors.map((actor) => actor.id),
tags: this.tags.map((tag) => tag.id),
matches: this.matches,
entity: this.entity?.id,
notify: this.notify,
email: this.email,
stashes: this.stashes.map((stash) => stash.id),
});
this.$emit('close', true);
} catch (error) {
this.error = error.message;
}
}
function addActor(actor) {
@@ -255,6 +333,26 @@ function removeTag(tag) {
this.tags = this.tags.filter((listedTag) => listedTag.id !== tag.id);
}
function addMatch() {
if (!this.matchExpression) {
return;
}
this.matches = this.matches.concat({
property: this.matchProperty,
expression: this.matchExpression,
});
this.matchProperty = 'title';
this.matchExpression = null;
this.events.emit('blur');
}
function removeMatch(removeIndex) {
this.matches = this.matches.filter((match, matchIndex) => matchIndex !== removeIndex);
}
function addStash(stash) {
if (!this.stashes.some((selectedStash) => selectedStash.id === stash.id)) {
this.stashes = this.stashes.concat(stash);
@@ -277,9 +375,13 @@ export default {
emits: ['close'],
data() {
return {
error: null,
actors: [],
tags: [],
entity: null,
matches: [],
matchProperty: 'title',
matchExpression: null,
notify: true,
email: false,
stashes: [],
@@ -290,10 +392,12 @@ export default {
addActor,
addAlert,
addEntity,
addMatch,
addTag,
addStash,
removeActor,
removeEntity,
removeMatch,
removeTag,
removeStash,
},
@@ -325,6 +429,15 @@ export default {
font-weight: normal;
}
.dialog-error {
padding: 1rem;
margin-bottom: 1rem;
background: var(--error);
color: var(--text-light);
font-weight: bold;
text-align: center;
}
.alert-heading {
margin: .75rem 0 .25rem 0;
}
@@ -338,6 +451,34 @@ export default {
font-size: 0;
}
.match {
display: flex;
align-items: center;
padding: .25rem 0;
font-family: inherit;
.remove {
position: relative;
top: -.1rem;
right: 0;
}
}
.match-property {
text-transform: capitalize;
color: var(--shadow);
}
.match-expression {
flex-grow: 1;
}
.match-slash {
padding: 0 .1rem;
color: var(--primary);
font-weight: bold;
}
.actors > .actor,
.entity,
.tag,
@@ -366,6 +507,14 @@ export default {
color: var(--text);
}
.pattern-tooltip {
display: flex;
gap: .5rem;
position: relative;
padding: .5rem;
overflow: hidden;
}
.remove {
width: 1rem;
height: 1rem;

View File

@@ -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> for <strong>${notification.alert.entity?.name || 'any channel'}</strong>`"
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>`"
icon="question5"
@click.prevent.stop
/>
@@ -145,12 +145,12 @@ export default {
default: 0,
},
},
emits: ['addAlert'],
data() {
return {
showAddAlert: false,
};
},
emits: ['addAlert'],
methods: {
checkNotifications,
checkNotification,

View File

@@ -125,6 +125,7 @@ function mounted() {
}
export default {
emits: ['open', 'close'],
data() {
return {
opened: false,
@@ -133,7 +134,6 @@ export default {
arrowOffset: 0,
};
},
emits: ['open', 'close'],
mounted,
methods: {
calculate,

View File

@@ -93,17 +93,43 @@
</div>
<div
v-if="alert.entity"
v-if="alert.entities.length > 0"
class="alert-section alert-trigger"
>
<h4 class="alert-heading">Channel</h4>
<h4 class="alert-heading">{{ alert.entities.length > 1 ? 'Channels' : 'Channel' }}</h4>
<Entity
v-if="alert.entity"
:entity="alert.entity"
v-for="entity in alert.entities"
:key="`${alert.id}${entity.id}`"
:entity="entity"
class="entity"
/>
</div>
<div
v-if="alert.matches.length > 0"
class="alert-section alert-trigger"
>
<h4 class="alert-heading">Matches</h4>
<ul class="alert-matches nolist">
<li
v-for="match in alert.matches"
:key="`match-${match.id}`"
class="match"
>
<span
v-if="match.expression.slice(0, 1) === '/' && match.expression.slice(-1) === '/'"
class="match-expression"
><span class="match-slash">/</span>{{ match.expression.slice(1, -1) }}<span class="match-slash">/</span></span>
<span
v-else
class="match-expression"
>{{ match.expression }}</span>
</li>
</ul>
</div>
</div>
</div>
</template>
@@ -227,26 +253,34 @@ export default {
}
.alert-actors,
.alert-tags {
.alert-tags,
.alert-matches {
display: flex;
grid-gap: .5rem;
}
.tag {
.tag,
.match {
color: var(--shadow-strong);
padding: .5rem;
border: solid 1px var(--shadow-hint);
font-size: .9rem;
font-weight: bold;
}
&:hover {
cursor: pointer;
border: solid 1px var(--primary);
}
.tag:hover {
cursor: pointer;
border: solid 1px var(--primary);
}
.entity {
width: 10rem;
height: 2.5rem;
}
.match-slash {
padding: 0 .1rem;
color: var(--primary);
font-weight: bold;
}
</style>