diff --git a/assets/img/icons/regexp.svg b/assets/img/icons/regexp.svg new file mode 100755 index 0000000..514c7b6 --- /dev/null +++ b/assets/img/icons/regexp.svg @@ -0,0 +1,7 @@ +<!-- Generated by IcoMoon.io --> +<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="21" height="16" viewBox="0 0 21 16"> +<path d="M14.964 7.134c-0.809-0.467-1.915-0.854-2.865-1.134 0.95-0.28 2.056-0.667 2.865-1.134 0.478-0.276 0.642-0.888 0.366-1.366s-0.888-0.642-1.366-0.366c-0.809 0.467-1.697 1.232-2.415 1.914 0.232-0.963 0.45-2.114 0.45-3.048 0-0.552-0.448-1-1-1s-1 0.448-1 1c0 0.934 0.218 2.086 0.45 3.048-0.717-0.683-1.606-1.447-2.415-1.914-0.478-0.276-1.090-0.112-1.366 0.366s-0.112 1.090 0.366 1.366c0.809 0.467 1.915 0.854 2.865 1.134-0.95 0.28-2.056 0.667-2.865 1.134-0.478 0.276-0.642 0.888-0.366 1.366s0.888 0.642 1.366 0.366c0.809-0.467 1.697-1.232 2.415-1.914-0.232 0.963-0.45 2.114-0.45 3.048 0 0.552 0.448 1 1 1s1-0.448 1-1c0-0.934-0.218-2.086-0.45-3.048 0.717 0.683 1.606 1.447 2.415 1.914 0.478 0.276 1.090 0.112 1.366-0.366s0.112-1.090-0.366-1.366z"></path> +<path d="M7 13.5c0 0.828-0.672 1.5-1.5 1.5s-1.5-0.672-1.5-1.5c0-0.828 0.672-1.5 1.5-1.5s1.5 0.672 1.5 1.5z"></path> +<path d="M0 16l4-16h2l-4 16z"></path> +<path d="M15 16l4-16h2l-4 16z"></path> +</svg> diff --git a/assets/img/icons/regexp2.svg b/assets/img/icons/regexp2.svg new file mode 100755 index 0000000..341a484 --- /dev/null +++ b/assets/img/icons/regexp2.svg @@ -0,0 +1,4 @@ +<!-- Generated by IcoMoon.io --> +<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"> +<path d="M15.15 0h-11.235c-0.562 0-1.106 0.442-1.21 0.983l-2.688 14.034c-0.104 0.541 0.271 0.983 0.833 0.983h11.235c0.562 0 1.106-0.442 1.21-0.983l2.688-14.034c0.104-0.541-0.271-0.983-0.833-0.983zM11.964 9.134c0.478 0.276 0.642 0.888 0.366 1.366s-0.888 0.642-1.366 0.366c-0.809-0.467-1.697-1.232-2.415-1.914 0.232 0.963 0.45 2.114 0.45 3.048 0 0.552-0.448 1-1 1s-1-0.448-1-1c0-0.934 0.218-2.085 0.45-3.048-0.717 0.683-1.606 1.447-2.415 1.914-0.478 0.276-1.090 0.112-1.366-0.366s-0.112-1.090 0.366-1.366c0.809-0.467 1.915-0.854 2.865-1.134-0.95-0.28-2.056-0.667-2.865-1.134-0.478-0.276-0.642-0.888-0.366-1.366s0.888-0.642 1.366-0.366c0.809 0.467 1.697 1.232 2.415 1.914-0.232-0.963-0.45-2.114-0.45-3.048 0-0.552 0.448-1 1-1s1 0.448 1 1c0 0.934-0.218 2.086-0.45 3.048 0.717-0.683 1.606-1.447 2.415-1.914 0.478-0.276 1.090-0.112 1.366 0.366s0.112 1.090-0.366 1.366c-0.809 0.467-1.915 0.854-2.865 1.134 0.95 0.28 2.056 0.667 2.865 1.134z"></path> +</svg> diff --git a/components/alerts/alerts.vue b/components/alerts/alerts.vue index 3997363..306d145 100644 --- a/components/alerts/alerts.vue +++ b/components/alerts/alerts.vue @@ -12,9 +12,60 @@ </button> </div> + <div class="filters"> + <input + v-model="query" + type="search" + class="input filters-search" + placeholder="Search alerts" + > + + <div class="filters-filters"> + <Icon + icon="star" + title="Only show actor alerts" + class="noselect" + :class="{ active: filterActors }" + @click="filterActors = !filterActors" + /> + + <Icon + icon="price-tags" + title="Only show tag alerts" + class="noselect" + :class="{ active: filterTags }" + @click="filterTags = !filterTags" + /> + + <Icon + icon="device_hub" + title="Only show channel alerts" + class="noselect" + :class="{ active: filterEntities }" + @click="filterEntities = !filterEntities" + /> + + <Icon + icon="regexp" + title="Only show expression alerts" + class="noselect" + :class="{ active: filterExpressions }" + @click="filterExpressions = !filterExpressions" + /> + + <Icon + icon="target3" + title="Only show uncombined alerts" + class="noselect uncombined" + :class="{ active: filterCombined }" + @click="filterCombined = !filterCombined" + /> + </div> + </div> + <ul class="alerts nolist"> <li - v-for="alert in alerts" + v-for="alert in filteredAlerts" :key="`alert-${alert.id}`" class="alert" > @@ -168,7 +219,7 @@ </template> <script setup> -import { ref, inject } from 'vue'; +import { ref, computed, inject } from 'vue'; import { format } from 'date-fns'; import AlertDialog from '#/components/alerts/create.vue'; @@ -181,6 +232,57 @@ const alerts = ref(pageContext.pageProps.alerts); const showAlertDialog = ref(false); const done = ref(true); +const query = ref(''); +const filterActors = ref(false); +const filterEntities = ref(false); +const filterTags = ref(false); +const filterExpressions = ref(false); +const filterCombined = ref(false); + +const filteredAlerts = computed(() => { + const queryRegex = new RegExp(query.value, 'i'); + + return alerts.value.filter((alert) => { + if (filterActors.value && alert.actors.length === 0) { + return false; + } + + if (filterEntities.value && alert.entities.length === 0) { + return false; + } + + if (filterTags.value && alert.tags.length === 0) { + return false; + } + + if (filterExpressions.value && alert.matches.length === 0) { + return false; + } + + if (filterCombined.value && [...alert.actors, ...alert.entities, ...alert.tags, ...alert.matches].length > 1) { + return false; + } + + if (alert.actors.some((actor) => queryRegex.test(actor.name))) { + return true; + } + + if (alert.tags.some((tag) => queryRegex.test(tag.name))) { + return true; + } + + if (alert.entities.some((entity) => queryRegex.test(entity.name))) { + return true; + } + + if (alert.matches.some((match) => queryRegex.test(match.expression))) { + return true; + } + + return false; + }); +}); + async function reloadAlerts() { alerts.value = await get('/alerts'); } @@ -223,6 +325,37 @@ async function removeAlert(alert) { margin-bottom: 1rem; } +.filters { + display: flex; + align-items: center; + padding-left: .5rem; + margin-bottom: .5rem; + + .input { + margin-right: 1rem; + } + + .icon { + width: 1.25rem; + height: 1.25rem; + padding: .25rem .5rem; + fill: var(--glass); + + &:hover { + fill: var(--primary); + cursor: pointer; + } + + &.active { + fill: var(--primary); + } + } + + .uncombined { + margin-left: .5rem; + } +} + .alert { padding: 0 0 0 .5rem; display: flex;