Merge pull request #405 from arabcoders/dev
Some checks failed
Build Native wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build Native wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, windows-latest) (push) Has been cancelled
Some checks failed
Build Native wrappers / build (amd64, ubuntu-latest) (push) Has been cancelled
Build Native wrappers / build (amd64, windows-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, macos-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, ubuntu-latest) (push) Has been cancelled
Build Native wrappers / build (arm64, windows-latest) (push) Has been cancelled
FEAT: Make it possible to limit notify target to specific presets.
This commit is contained in:
commit
c528e2b557
7 changed files with 197 additions and 76 deletions
|
|
@ -494,7 +494,12 @@ class DownloadQueue(metaclass=Singleton):
|
|||
|
||||
dlInfo.info.status = "not_live"
|
||||
dlInfo.info.msg = nMessage.replace(f" '{dlInfo.info.title}'", "")
|
||||
await self._notify.emit(Events.LOG_INFO, data={"lowPriority": True}, title=nTitle, message=nMessage)
|
||||
await self._notify.emit(
|
||||
Events.LOG_INFO,
|
||||
data={"preset": dlInfo.info.preset, "lowPriority": True},
|
||||
title=nTitle,
|
||||
message=nMessage,
|
||||
)
|
||||
|
||||
itemDownload: Download = self.done.put(dlInfo)
|
||||
elif len(entry.get("formats", [])) < 1:
|
||||
|
|
@ -511,7 +516,12 @@ class DownloadQueue(metaclass=Singleton):
|
|||
dlInfo.info.status = "error"
|
||||
itemDownload = self.done.put(dlInfo)
|
||||
|
||||
await self._notify.emit(Events.LOG_WARNING, data={"logs": text_logs}, title=nTitle, message=nMessage)
|
||||
await self._notify.emit(
|
||||
Events.LOG_WARNING,
|
||||
data={"preset": dlInfo.info.preset, "logs": text_logs},
|
||||
title=nTitle,
|
||||
message=nMessage,
|
||||
)
|
||||
elif is_premiere and self.config.prevent_live_premiere:
|
||||
nStore = "history"
|
||||
nTitle = "Premiere Video"
|
||||
|
|
@ -546,7 +556,9 @@ class DownloadQueue(metaclass=Singleton):
|
|||
nStore = "history"
|
||||
nEvent = Events.ITEM_MOVED
|
||||
nTitle = "Premiering right now"
|
||||
await self._notify.emit(Events.LOG_INFO, title=nTitle, message=nMessage)
|
||||
await self._notify.emit(
|
||||
Events.LOG_INFO, data={"preset": dlInfo.info.preset}, title=nTitle, message=nMessage
|
||||
)
|
||||
else:
|
||||
nEvent = Events.ITEM_ADDED
|
||||
nTitle = "Item Added"
|
||||
|
|
@ -559,7 +571,9 @@ class DownloadQueue(metaclass=Singleton):
|
|||
|
||||
await self._notify.emit(
|
||||
nEvent,
|
||||
data={"to": nStore, "item": itemDownload.info} if Events.ITEM_MOVED == nEvent else itemDownload.info,
|
||||
data={"to": nStore, "preset": itemDownload.info.preset, "item": itemDownload.info}
|
||||
if Events.ITEM_MOVED == nEvent
|
||||
else itemDownload.info,
|
||||
title=nTitle,
|
||||
message=nMessage,
|
||||
)
|
||||
|
|
@ -664,7 +678,9 @@ class DownloadQueue(metaclass=Singleton):
|
|||
if item.is_archived():
|
||||
message: str = f"The URL '{item.url}' is already downloaded and recorded in archive."
|
||||
LOG.error(message)
|
||||
await self._notify.emit(Events.LOG_INFO, title="Already Downloaded", message=message)
|
||||
await self._notify.emit(
|
||||
Events.LOG_INFO, data={"preset": item.preset}, title="Already Downloaded", message=message
|
||||
)
|
||||
return {"status": "error", "msg": message}
|
||||
|
||||
started: float = time.perf_counter()
|
||||
|
|
@ -777,7 +793,7 @@ class DownloadQueue(metaclass=Singleton):
|
|||
self.done.put(item)
|
||||
await self._notify.emit(
|
||||
Events.ITEM_MOVED,
|
||||
data={"to": "history", "item": item.info},
|
||||
data={"to": "history", "preset": item.info.preset, "item": item.info},
|
||||
title="Download Cancelled",
|
||||
message=f"Download '{item.info.title}' has been cancelled.",
|
||||
)
|
||||
|
|
@ -1014,7 +1030,7 @@ class DownloadQueue(metaclass=Singleton):
|
|||
_tasks.append(
|
||||
self._notify.emit(
|
||||
Events.ITEM_MOVED,
|
||||
data={"to": "history", "item": entry.info},
|
||||
data={"to": "history", "preset": entry.info.preset, "item": entry.info},
|
||||
title=nTitle,
|
||||
message=nMessage,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ from .BackgroundWorker import BackgroundWorker
|
|||
from .config import Config
|
||||
from .encoder import Encoder
|
||||
from .Events import Event, EventBus, Events
|
||||
from .ItemDTO import ItemDTO
|
||||
from .ItemDTO import Item, ItemDTO
|
||||
from .Presets import Preset, Presets
|
||||
from .Singleton import Singleton
|
||||
from .Utils import validate_uuid
|
||||
|
||||
|
|
@ -71,7 +72,8 @@ class Target:
|
|||
|
||||
id: str
|
||||
name: str
|
||||
on: list[str]
|
||||
on: list[str] = field(default_factory=list)
|
||||
presets: list[str] = field(default_factory=list)
|
||||
request: TargetRequest
|
||||
|
||||
def serialize(self) -> dict:
|
||||
|
|
@ -79,6 +81,7 @@ class Target:
|
|||
"id": self.id,
|
||||
"name": self.name,
|
||||
"on": self.on,
|
||||
"presets": self.presets,
|
||||
"request": self.request.serialize(),
|
||||
}
|
||||
|
||||
|
|
@ -144,11 +147,11 @@ class Notification(metaclass=Singleton):
|
|||
Notification._instance = self
|
||||
config: Config = config or Config.get_instance()
|
||||
|
||||
self._debug = config.debug
|
||||
self._debug: bool = config.debug
|
||||
self._file: Path = Path(file) if file else Path(config.config_path).joinpath("notifications.json")
|
||||
self._client: httpx.AsyncClient = client or httpx.AsyncClient()
|
||||
self._encoder: Encoder = encoder or Encoder()
|
||||
self._version = config.app_version
|
||||
self._version: str = config.app_version
|
||||
self._offload: BackgroundWorker = background_worker or BackgroundWorker.get_instance()
|
||||
|
||||
if self._file.exists() and "600" != self._file.stat().st_mode:
|
||||
|
|
@ -212,7 +215,7 @@ class Notification(metaclass=Singleton):
|
|||
if not self._file.exists() or self._file.stat().st_size < 1:
|
||||
return self
|
||||
|
||||
targets = []
|
||||
targets: list = []
|
||||
|
||||
try:
|
||||
LOG.info(f"Loading '{self._file}'.")
|
||||
|
|
@ -255,6 +258,7 @@ class Notification(metaclass=Singleton):
|
|||
id=target.get("id"),
|
||||
name=target.get("name"),
|
||||
on=target.get("on", []),
|
||||
presets=target.get("presets", []),
|
||||
request=TargetRequest(
|
||||
type=target.get("request", {}).get("type", "json"),
|
||||
method=target.get("request", {}).get("method", "POST"),
|
||||
|
|
@ -317,8 +321,8 @@ class Notification(metaclass=Singleton):
|
|||
msg = "Invalid notification target. Invalid 'on' event list found."
|
||||
raise ValueError(msg)
|
||||
|
||||
removed_events = []
|
||||
all_events = NotificationEvents.get_events().values()
|
||||
removed_events: list = []
|
||||
all_events: dict[str, str] = NotificationEvents.get_events().values()
|
||||
for e in target["on"]:
|
||||
if e not in all_events:
|
||||
removed_events.append(e)
|
||||
|
|
@ -329,6 +333,24 @@ class Notification(metaclass=Singleton):
|
|||
msg: str = f"Invalid notification target. Invalid events '{', '.join(removed_events)}' found."
|
||||
raise ValueError(msg)
|
||||
|
||||
if "presets" in target:
|
||||
if not isinstance(target["presets"], list):
|
||||
msg = "Invalid notification target. Invalid 'presets' list found."
|
||||
raise ValueError(msg)
|
||||
|
||||
removed_presets: list = []
|
||||
all_presets: list[Preset] = Presets.get_instance().get_all()
|
||||
|
||||
for p in target["presets"]:
|
||||
if p not in [ap.name for ap in all_presets]:
|
||||
removed_presets.append(p)
|
||||
target["presets"].remove(p)
|
||||
continue
|
||||
|
||||
if len(removed_presets) > 0 and len(target["presets"]) < 1:
|
||||
msg: str = f"Invalid notification target. Invalid presets '{', '.join(removed_presets)}' found."
|
||||
raise ValueError(msg)
|
||||
|
||||
if "headers" in target["request"]:
|
||||
if not isinstance(target["request"]["headers"], list):
|
||||
msg = "Invalid notification target. Invalid headers list found."
|
||||
|
|
@ -360,6 +382,9 @@ class Notification(metaclass=Singleton):
|
|||
if len(target.on) > 0 and ev.event not in target.on and "test" != ev.event:
|
||||
continue
|
||||
|
||||
if "test" != ev.event and not self._check_preset(target, ev):
|
||||
continue
|
||||
|
||||
if not target.request.url.startswith("http"):
|
||||
apprise_targets.append(target)
|
||||
else:
|
||||
|
|
@ -373,6 +398,29 @@ class Notification(metaclass=Singleton):
|
|||
|
||||
return tasks
|
||||
|
||||
def _check_preset(self, target: Target, ev: Event) -> bool:
|
||||
if len(target.presets) < 1:
|
||||
return True
|
||||
|
||||
if not isinstance(ev.data, (Item, ItemDTO, dict)):
|
||||
return False
|
||||
|
||||
preset_name: str | None = None
|
||||
|
||||
if isinstance(ev.data, Item):
|
||||
preset_name = ev.data.preset
|
||||
|
||||
if isinstance(ev.data, ItemDTO):
|
||||
preset_name = ev.data.preset
|
||||
|
||||
if isinstance(ev.data, dict):
|
||||
preset_name = ev.data.get("preset", None)
|
||||
|
||||
if not preset_name:
|
||||
return False
|
||||
|
||||
return preset_name in target.presets
|
||||
|
||||
async def _apprise(self, target: list[Target], ev: Event) -> dict:
|
||||
if not target or not isinstance(target, list):
|
||||
return {}
|
||||
|
|
@ -406,7 +454,7 @@ class Notification(metaclass=Singleton):
|
|||
try:
|
||||
LOG.info(f"Sending Notification event '{ev.event}: {ev.id}' to '{target.name}'.")
|
||||
|
||||
reqBody = {
|
||||
reqBody: dict[str, Any] = {
|
||||
"method": target.request.method.upper(),
|
||||
"url": target.request.url,
|
||||
"headers": {
|
||||
|
|
@ -423,7 +471,7 @@ class Notification(metaclass=Singleton):
|
|||
for h in target.request.headers:
|
||||
reqBody["headers"][h.key] = h.value
|
||||
|
||||
body_key = "json" if "json" == target.request.type.lower() else "data"
|
||||
body_key: str = "json" if "json" == target.request.type.lower() else "data"
|
||||
reqBody[body_key] = self._deep_unpack(ev.serialize())
|
||||
|
||||
if "data" != target.request.data_key:
|
||||
|
|
@ -437,11 +485,15 @@ class Notification(metaclass=Singleton):
|
|||
|
||||
response = await self._client.request(**reqBody)
|
||||
|
||||
respData = {"url": target.request.url, "status": response.status_code, "text": response.text}
|
||||
respData: dict[str, Any] = {
|
||||
"url": target.request.url,
|
||||
"status": response.status_code,
|
||||
"text": response.text,
|
||||
}
|
||||
|
||||
msg = f"Notification target '{target.name}' Responded to event '{ev.event}: {ev.id}' with status '{response.status_code}'."
|
||||
msg: str = f"Notification target '{target.name}' Responded to event '{ev.event}: {ev.id}' with status '{response.status_code}'."
|
||||
if self._debug and respData.get("text"):
|
||||
msg += f" body '{respData.get('text','??')}'."
|
||||
msg += f" body '{respData.get('text', '??')}'."
|
||||
|
||||
LOG.info(msg)
|
||||
|
||||
|
|
@ -449,7 +501,7 @@ class Notification(metaclass=Singleton):
|
|||
except Exception as e:
|
||||
err_msg = str(e)
|
||||
if not err_msg:
|
||||
err_msg = type(e).__name__
|
||||
err_msg: str = type(e).__name__
|
||||
LOG.error(f"Error sending Notification event '{ev.event}: {ev.id}' to '{target.name}'. '{err_msg!s}'.")
|
||||
return {"url": target.request.url, "status": 500, "text": str(ev)}
|
||||
|
||||
|
|
|
|||
|
|
@ -434,13 +434,13 @@ class Tasks(metaclass=Singleton):
|
|||
_tasks = [
|
||||
self._notify.emit(
|
||||
Events.TASK_DISPATCHED,
|
||||
data=status,
|
||||
data={**status, "preset": task.preset} if status else {"preset": task.preset},
|
||||
title=f"Task '{task.name}' dispatched",
|
||||
message=f"Task '{task.name}' dispatched at '{timeNow}'.",
|
||||
),
|
||||
self._notify.emit(
|
||||
Events.LOG_SUCCESS,
|
||||
data={"lowPriority": True},
|
||||
data={"preset": task.preset, "lowPriority": True},
|
||||
title="Task completed",
|
||||
message=f"Task '{task.name}' completed in '{ended - started:.2f}'.",
|
||||
),
|
||||
|
|
@ -451,6 +451,7 @@ class Tasks(metaclass=Singleton):
|
|||
LOG.error(f"Failed to execute '{task.name}' at '{timeNow}'. '{e!s}'.")
|
||||
await self._notify.emit(
|
||||
Events.LOG_ERROR,
|
||||
data={"preset": task.preset},
|
||||
title="Task failed",
|
||||
message=f"Failed to execute '{task.name}'. '{e!s}'",
|
||||
)
|
||||
|
|
|
|||
|
|
@ -15,18 +15,21 @@ async def add_url(queue: DownloadQueue, notify: EventBus, sid: str, data: dict):
|
|||
await notify.emit(Events.LOG_ERROR, title="Invalid request", message="No URL provided.", to=sid)
|
||||
return
|
||||
|
||||
item: Item = Item.format(data)
|
||||
try:
|
||||
status = await queue.add(item=Item.format(data))
|
||||
status = await queue.add(item=item)
|
||||
await notify.emit(
|
||||
event=Events.ITEM_STATUS,
|
||||
title="Adding URL",
|
||||
message=f"Adding URL '{url}' to the download queue.",
|
||||
data=status,
|
||||
data={**status, "preset": item.preset} if status else {"preset": item.preset},
|
||||
to=sid,
|
||||
)
|
||||
except ValueError as e:
|
||||
LOG.exception(e)
|
||||
await notify.emit(Events.LOG_ERROR, title="Error Adding URL", message=str(e), to=sid)
|
||||
await notify.emit(
|
||||
Events.LOG_ERROR, data={"preset": item.preset}, title="Error Adding URL", message=str(e), to=sid
|
||||
)
|
||||
|
||||
|
||||
@route(RouteType.SOCKET, "item_cancel", "item_cancel")
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@
|
|||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<span class="help">
|
||||
<span class="help is-bold">
|
||||
<span class="icon"><i class="fa-solid fa-info" /></span>
|
||||
<span>You can use this field to populate the data, using shared string.</span>
|
||||
</span>
|
||||
|
|
@ -63,7 +63,7 @@
|
|||
<input type="text" class="input" id="name" v-model="form.name" :disabled="addInProgress" required>
|
||||
<span class="icon is-small is-left"><i class="fa-solid fa-user" /></span>
|
||||
</div>
|
||||
<span class="help">
|
||||
<span class="help is-bold">
|
||||
<span class="icon"><i class="fa-solid fa-info" /></span>
|
||||
<span>The notification target name, this is used to identify the target in the logs and
|
||||
notifications.</span>
|
||||
|
|
@ -81,11 +81,13 @@
|
|||
required>
|
||||
<span class="icon is-small is-left"><i class="fa-solid fa-link" /></span>
|
||||
</div>
|
||||
<span class="help">
|
||||
<span class="help is-bold">
|
||||
<span class="icon"><i class="fa-solid fa-info" /></span>
|
||||
<span class="is-bold">The URL to send the notification to. It can be regular http/https endpoint.
|
||||
or <NuxtLink target="blank" href="https://github.com/caronc/apprise?tab=readme-ov-file#readme">
|
||||
Apprise</NuxtLink> URL.</span>
|
||||
<span>
|
||||
The URL to send the notification to. It can be regular http/https endpoint. or <NuxtLink
|
||||
target="blank" href="https://github.com/caronc/apprise?tab=readme-ov-file#readme">Apprise
|
||||
</NuxtLink> URL.
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -105,7 +107,7 @@
|
|||
</div>
|
||||
<span class="icon is-small is-left"><i class="fa-solid fa-tv" /></span>
|
||||
</div>
|
||||
<span class="help">
|
||||
<span class="help is-bold">
|
||||
<span class="icon"><i class="fa-solid fa-info" /></span>
|
||||
<span>
|
||||
The request method to use when sending the notification. This can be any of the standard HTTP
|
||||
|
|
@ -130,7 +132,7 @@
|
|||
</div>
|
||||
<span class="icon is-small is-left"><i class="fa-solid fa-tv" /></span>
|
||||
</div>
|
||||
<span class="help">
|
||||
<span class="help is-bold">
|
||||
<span class="icon"><i class="fa-solid fa-info" /></span>
|
||||
<span>
|
||||
The request type to use when sending the notification. This can be <code>JSON</code> or
|
||||
|
|
@ -140,7 +142,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column is-12-mobile" :class="{ 'is-6-tablet': !isApprise, 'is-12': isApprise }">
|
||||
<div class="column is-6-tablet is-12-mobile">
|
||||
<div class="field">
|
||||
<label class="label is-inline" for="on">
|
||||
Select Events
|
||||
|
|
@ -158,7 +160,7 @@
|
|||
</div>
|
||||
<span class="icon is-small is-left"><i class="fa-solid fa-paper-plane" /></span>
|
||||
</div>
|
||||
<span class="help">
|
||||
<span class="help is-bold">
|
||||
<span class="icon"><i class="fa-solid fa-info" /></span>
|
||||
<span>
|
||||
Subscribe to the events you want to listen for. When the event is triggered, the notification will
|
||||
|
|
@ -169,7 +171,43 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column is-6-tablet is-12-mobile" v-if="!isApprise">
|
||||
<div class="column is-6-tablet is-12-mobile">
|
||||
<div class="field">
|
||||
<label class="label is-inline" for="on">
|
||||
Select Presets
|
||||
<template v-if="form.presets.length > 0">
|
||||
- <NuxtLink @click="form.presets = []">Clear selection</NuxtLink>
|
||||
</template>
|
||||
</label>
|
||||
<div class="control has-icons-left">
|
||||
<div class="select is-multiple is-fullwidth">
|
||||
<select id="on" class="is-fullwidth" v-model="form.presets" :disabled="addInProgress" multiple>
|
||||
<optgroup label="Custom presets" v-if="config?.presets.filter(p => !p?.default).length > 0">
|
||||
<option v-for="item in filter_presets(false)" :key="item.id" :value="item.name">
|
||||
{{ item.name }}
|
||||
</option>
|
||||
</optgroup>
|
||||
<optgroup label="Default presets">
|
||||
<option v-for="item in filter_presets(true)" :key="item.id" :value="item.name">
|
||||
{{ item.name }}
|
||||
</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<span class="icon is-small is-left"><i class="fa-solid fa-sliders" /></span>
|
||||
</div>
|
||||
<span class="help is-bold">
|
||||
<span class="icon"><i class="fa-solid fa-info" /></span>
|
||||
<span>
|
||||
Select the presets you want to listen for. If you select presets, only events that reference those
|
||||
presets will trigger the notification. If no presets are selected, the notification will be sent
|
||||
for all presets.
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="column is-12" v-if="!isApprise">
|
||||
<div class="field">
|
||||
<label class="label is-inline" for="data_key">
|
||||
Data field
|
||||
|
|
@ -179,7 +217,7 @@
|
|||
:disabled="addInProgress" required>
|
||||
<span class="icon is-small is-left"><i class="fa-solid fa-key" /></span>
|
||||
</div>
|
||||
<span class="help">
|
||||
<span class="help is-bold">
|
||||
<span class="icon"><i class="fa-solid fa-info" /></span>
|
||||
<span>
|
||||
The field name to use when sending the notification. This is used to identify the data in the
|
||||
|
|
@ -206,7 +244,7 @@
|
|||
<span class="icon is-small is-left"><i class="fa-solid fa-key" /></span>
|
||||
</div>
|
||||
</div>
|
||||
<span class="help">
|
||||
<span class="help is-bold">
|
||||
<span class="icon"><i class="fa-solid fa-info" /></span>
|
||||
<span>The header key to send with the notification.</span>
|
||||
</span>
|
||||
|
|
@ -219,7 +257,7 @@
|
|||
<span class="icon is-small is-left"><i class="fa-solid fa-v" /></span>
|
||||
</div>
|
||||
</div>
|
||||
<span class="help">
|
||||
<span class="help is-bold">
|
||||
<span class="icon"><i class="fa-solid fa-info" /></span>
|
||||
<span>The header value to send with the notification.</span>
|
||||
</span>
|
||||
|
|
@ -234,7 +272,7 @@
|
|||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<span class="help">
|
||||
<span class="help is-bold">
|
||||
<span class="icon"><i class="fa-solid fa-exclamation" /></span>
|
||||
<span class="has-text-danger">
|
||||
If header key or value is empty, the header will not be sent.
|
||||
|
|
@ -274,6 +312,7 @@ import type { notification, notificationImport } from '~/types/notification'
|
|||
const emitter = defineEmits(['cancel', 'submit'])
|
||||
const toast = useNotification()
|
||||
const box = useConfirm()
|
||||
const config = useConfigStore()
|
||||
|
||||
const props = defineProps({
|
||||
reference: {
|
||||
|
|
@ -396,7 +435,17 @@ const importItem = async () => {
|
|||
|
||||
if (item.on) {
|
||||
form.on = item.on
|
||||
}
|
||||
|
||||
if (item.presets) {
|
||||
item.presets.forEach(p => {
|
||||
if (!config.presets.find(cp => cp.name === p)) {
|
||||
return
|
||||
}
|
||||
if (!form.presets.includes(p)) {
|
||||
form.presets.push(p)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
import_string.value = ''
|
||||
|
|
@ -407,4 +456,5 @@ const importItem = async () => {
|
|||
}
|
||||
|
||||
const isApprise = computed(() => form.request.url && !form.request.url.startsWith('http'))
|
||||
const filter_presets = (flag: boolean = true) => config.presets.filter(item => item.default === flag)
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@
|
|||
</div>
|
||||
<div class="is-hidden-mobile">
|
||||
<span class="subtitle">
|
||||
Send notifications to your servers based on specified events.
|
||||
Send notifications to your webhooks based on specified events or presets.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -76,15 +76,20 @@
|
|||
<tbody>
|
||||
<tr v-for="item in notifications" :key="item.id">
|
||||
<td class="is-text-overflow is-vcentered">
|
||||
<div>
|
||||
<div class="is-bold">
|
||||
{{ item.request.method.toUpperCase() }}({{ ucFirst(item.request.type) }}) @
|
||||
<NuxtLink target="_blank" :href="item.request.url">{{ item.name }}</NuxtLink>
|
||||
<NuxtLink target="_blank" :href="item.request.url">{{ item.name }}</NuxtLink>
|
||||
</div>
|
||||
<div class="is-unselectable">
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fa-solid fa-list-ul" /></span>
|
||||
<span>On: {{ join_events(item.on) }}</span>
|
||||
</span>
|
||||
|
||||
<span class="icon-text">
|
||||
<span class="icon"><i class="fa-solid fa-sliders" /></span>
|
||||
<span>Presets: {{ join_presets(item.presets) }}</span>
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="is-vcentered is-items-center">
|
||||
|
|
@ -139,6 +144,10 @@
|
|||
<span class="icon"><i class="fa-solid fa-list-ul" /></span>
|
||||
<span>On: {{ join_events(item.on) }}</span>
|
||||
</p>
|
||||
<p>
|
||||
<span class="icon"><i class="fa-solid fa-sliders" /></span>
|
||||
<span>Presets: {{ join_presets(item.presets) }}</span>
|
||||
</p>
|
||||
<p v-if="item.request?.headers && item.request.headers.length > 0">
|
||||
<span class="icon"><i class="fa-solid fa-heading" /></span>
|
||||
<span>{{item.request.headers.map(h => h.key).join(', ')}}</span>
|
||||
|
|
@ -186,14 +195,21 @@
|
|||
to ensure that the exported data does not contain any sensitive information for sharing.
|
||||
</li>
|
||||
<li>
|
||||
When you set the request type as <code>Form</code>, the event data will be JSON encoded and sent as the
|
||||
and sent as <code>...&data_key=json_string</code>, only the <code>data</code> field will be JSON encoded.
|
||||
When you set the request type as <code>Form</code>, the event data will be JSON encoded and sent as
|
||||
<code>...&data_key=json_string</code>, only the <code>data</code> field will be JSON encoded.
|
||||
The other keys <code>id</code>, <code>event</code> and <code>created_at</code> will be sent as they are.
|
||||
</li>
|
||||
<li>We also send two special headers <code>X-Event-ID</code> and <code>X-Event</code> with the request.</li>
|
||||
<li>Support for <code>Apprise URLs</code> is in beta and subject to many changes to come, currently the
|
||||
message field fallback to JSON encoded string of the event if there there is custom message set by us for
|
||||
that particular event.</li>
|
||||
message field fallback to JSON encoded string of the event if no custom message set by us for that
|
||||
particular event.</li>
|
||||
<li>
|
||||
If you have selected specific presets or events, this will take priority, For example, if you limited the
|
||||
target to <code>default</code> preset and selected <code>ALL</code> events, only events that reference the
|
||||
<code>default</code> preset will be sent to that target. Like wise, if you have limited both events and
|
||||
presets, then ONLY events that satisfy both conditions will be sent to that target. Only the
|
||||
<code>test</code> events can bypass these conditions.
|
||||
</li>
|
||||
</ul>
|
||||
</Message>
|
||||
</div>
|
||||
|
|
@ -213,17 +229,15 @@ const isMobile = useMediaQuery({ maxWidth: 1024 })
|
|||
|
||||
const allowedEvents = ref<string[]>([])
|
||||
const notifications = ref<notification[]>([])
|
||||
const target = ref<notification>({
|
||||
|
||||
const defaultState = (): notification => ({
|
||||
name: '',
|
||||
on: [],
|
||||
request: {
|
||||
method: 'POST',
|
||||
url: '',
|
||||
type: 'json',
|
||||
headers: [],
|
||||
data_key: '',
|
||||
},
|
||||
presets: [],
|
||||
request: { method: 'POST', url: '', type: 'json', headers: [], data_key: 'data' },
|
||||
})
|
||||
|
||||
const target = ref<notification>(defaultState())
|
||||
const targetRef = ref<string | null>('')
|
||||
const toggleForm = ref(false)
|
||||
const isLoading = ref(false)
|
||||
|
|
@ -274,17 +288,7 @@ const reloadContent = async (fromMounted = false) => {
|
|||
}
|
||||
|
||||
const resetForm = (closeForm = false) => {
|
||||
target.value = {
|
||||
name: '',
|
||||
on: [],
|
||||
request: {
|
||||
method: 'POST',
|
||||
url: '',
|
||||
type: 'json',
|
||||
headers: [],
|
||||
data_key: '',
|
||||
},
|
||||
}
|
||||
target.value = defaultState()
|
||||
targetRef.value = null
|
||||
if (closeForm) {
|
||||
toggleForm.value = false
|
||||
|
|
@ -331,13 +335,7 @@ const deleteItem = async (item: notification) => {
|
|||
toast.success('Notification target deleted.')
|
||||
}
|
||||
|
||||
const updateItem = async ({
|
||||
reference,
|
||||
item,
|
||||
}: {
|
||||
reference: string | null;
|
||||
item: notification;
|
||||
}) => {
|
||||
const updateItem = async ({ reference, item }: { reference: string | null, item: notification }) => {
|
||||
if (reference) {
|
||||
const index = notifications.value.findIndex(i => i?.id === reference)
|
||||
if (0 <= index) {
|
||||
|
|
@ -369,8 +367,8 @@ const editItem = (item: notification) => {
|
|||
toggleForm.value = true
|
||||
}
|
||||
|
||||
const join_events = (events: string[]) =>
|
||||
!events || events.length < 1 ? 'ALL' : events.map(e => ucFirst(e)).join(', ')
|
||||
const join_events = (events: Array<string>) => !events || events.length < 1 ? 'ALL' : events.map(e => ucFirst(e)).join(', ')
|
||||
const join_presets = (presets: Array<string>) => !presets || presets.length < 1 ? 'ALL' : presets.map(e => ucFirst(e)).join(', ')
|
||||
|
||||
const sendTest = async () => {
|
||||
if (true !== (await box.confirm('Send test notification?'))) {
|
||||
|
|
|
|||
3
ui/app/types/notification.d.ts
vendored
3
ui/app/types/notification.d.ts
vendored
|
|
@ -15,7 +15,8 @@ type notification = {
|
|||
id?: string;
|
||||
name: string;
|
||||
request: notificationRequest;
|
||||
on: string[];
|
||||
on: Array<string>;
|
||||
presets: Array<string>;
|
||||
raw?: boolean;
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue