mirror of
https://github.com/donaldzou/WGDashboard.git
synced 2025-10-03 15:56:17 +00:00
Finished most of the webhook UI
This commit is contained in:
@@ -1401,6 +1401,18 @@ def API_WebHooks_DeleteWebHook():
|
||||
status, msg = DashboardWebHooks.DeleteWebHook(data)
|
||||
return ResponseObject(status, msg)
|
||||
|
||||
@app.get(f'{APP_PREFIX}/api/webHooks/getWebHookSessions')
|
||||
def API_WebHooks_GetWebHookSessions():
|
||||
webhookID = request.args.get('WebHookID')
|
||||
if not webhookID:
|
||||
return ResponseObject(False, "Please provide WebHookID")
|
||||
|
||||
webHook = DashboardWebHooks.SearchWebHookByID(webhookID)
|
||||
if not webHook:
|
||||
return ResponseObject(False, "Webhook does not exist")
|
||||
|
||||
return ResponseObject(data=DashboardWebHooks.GetWebHookSessions(webHook))
|
||||
|
||||
|
||||
'''
|
||||
Index Page
|
||||
|
@@ -69,6 +69,7 @@ class DashboardWebHooks:
|
||||
db.Column('EndDate',
|
||||
(db.DATETIME if DashboardConfig.GetConfig("Database", "type")[1] == 'sqlite' else db.TIMESTAMP),
|
||||
),
|
||||
db.Column('Data', db.JSON),
|
||||
db.Column('Status', db.INTEGER),
|
||||
db.Column('Logs', db.JSON)
|
||||
)
|
||||
@@ -91,6 +92,17 @@ class DashboardWebHooks:
|
||||
self.__getWebHooks()
|
||||
return list(map(lambda x : x.model_dump(), self.WebHooks))
|
||||
|
||||
def GetWebHookSessions(self, webHook: WebHook):
|
||||
with self.engine.connect() as conn:
|
||||
sessions = conn.execute(
|
||||
self.webHookSessionsTable.select().where(
|
||||
self.webHookSessionsTable.c.WebHookID == webHook.WebHookID
|
||||
).order_by(
|
||||
db.desc(self.webHookSessionsTable.c.StartDate)
|
||||
)
|
||||
).mappings().fetchall()
|
||||
return sessions
|
||||
|
||||
def CreateWebHook(self) -> WebHook:
|
||||
return WebHook(WebHookID=str(uuid.uuid4()))
|
||||
|
||||
@@ -101,6 +113,13 @@ class DashboardWebHooks:
|
||||
return None
|
||||
return first
|
||||
|
||||
def SearchWebHookByID(self, webHookID: str) -> WebHook | None:
|
||||
try:
|
||||
first = next(filter(lambda x : x.WebHookID == webHookID, self.WebHooks))
|
||||
except StopIteration:
|
||||
return None
|
||||
return first
|
||||
|
||||
def UpdateWebHook(self, webHook: dict[str, str]) -> tuple[bool, str] | tuple[bool, None]:
|
||||
try:
|
||||
webHook = WebHook(**webHook)
|
||||
@@ -154,6 +173,7 @@ class DashboardWebHooks:
|
||||
return False
|
||||
self.__getWebHooks()
|
||||
subscribedWebHooks = filter(lambda webhook: action in webhook.SubscribedActions, self.WebHooks)
|
||||
data['action'] = action
|
||||
for i in subscribedWebHooks:
|
||||
try:
|
||||
t = threading.Thread(target=WebHookSession, args=(i,data), daemon=True)
|
||||
@@ -171,11 +191,11 @@ class WebHookSession:
|
||||
self.webHook = webHook
|
||||
self.sessionID = str(uuid.uuid4())
|
||||
self.webHookSessionLogs: WebHookSessionLogs = WebHookSessionLogs()
|
||||
|
||||
data['time'] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
self.time = datetime.now()
|
||||
data['time'] = self.time.strftime("%Y-%m-%d %H:%M:%S")
|
||||
data['webhook_id'] = webHook.WebHookID
|
||||
data['webhook_session'] = self.sessionID
|
||||
data['content'] = 'hi!'
|
||||
self.data = data
|
||||
self.Prepare()
|
||||
self.Execute(data)
|
||||
|
||||
@@ -185,6 +205,8 @@ class WebHookSession:
|
||||
self.webHookSessionsTable.insert().values({
|
||||
"WebHookSessionID": self.sessionID,
|
||||
"WebHookID": self.webHook.WebHookID,
|
||||
"Data": self.data,
|
||||
"StartDate": self.time,
|
||||
"Status": -1,
|
||||
"Logs": self.webHookSessionLogs.model_dump()
|
||||
})
|
||||
@@ -243,10 +265,8 @@ class WebHookSession:
|
||||
break
|
||||
except requests.exceptions.RequestException as e:
|
||||
self.UpdateSessionLog(1, f"Attempt #{i + 1}/5. Request errored. Reason: " + str(e))
|
||||
time.sleep(5)
|
||||
time.sleep(10)
|
||||
|
||||
if not success:
|
||||
self.UpdateSessionLog(1, "Webhook request failed & terminated.")
|
||||
self.UpdateStatus(1)
|
||||
|
||||
|
||||
self.UpdateStatus(1)
|
@@ -3,6 +3,7 @@ import LocaleText from "@/components/text/localeText.vue";
|
||||
import { fetchGet } from "@/utilities/fetch.js"
|
||||
import {onMounted, ref} from "vue";
|
||||
import AddWebHook from "@/components/settingsComponent/dashboardWebHooksComponents/addWebHook.vue";
|
||||
import WebHookSessions from "@/components/settingsComponent/dashboardWebHooksComponents/webHookSessions.vue";
|
||||
const webHooks = ref([])
|
||||
const webHooksLoaded = ref(false)
|
||||
|
||||
@@ -19,6 +20,7 @@ const getWebHooks = async () => {
|
||||
const addWebHook = ref(false)
|
||||
const selectedWebHook = ref(undefined)
|
||||
|
||||
const view = ref("edit")
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -67,12 +69,43 @@ const selectedWebHook = ref(undefined)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-8 overflow-scroll h-100" >
|
||||
<div class="col-sm-8 overflow-scroll h-100" v-if="selectedWebHook">
|
||||
<nav class="navbar navbar-expand-lg bg-body-tertiary sticky-top">
|
||||
<div class="container-fluid">
|
||||
<div>
|
||||
<ul class="navbar-nav gap-2">
|
||||
<li class="nav-item">
|
||||
<a
|
||||
@click="view = 'edit'"
|
||||
:class="{active: view === 'edit'}"
|
||||
class="nav-link rounded-3" role="button">Edit</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a
|
||||
:class="{active: view === 'sessions'}"
|
||||
@click="view = 'sessions'"
|
||||
class="nav-link rounded-3" role="button">Sessions</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<AddWebHook
|
||||
v-if="view === 'edit'"
|
||||
:key="selectedWebHook"
|
||||
v-if="selectedWebHook"
|
||||
@delete="getWebHooks(); selectedWebHook = undefined;"
|
||||
:webHook="selectedWebHook" @refresh="getWebHooks()" ></AddWebHook>
|
||||
<Suspense v-else-if="view === 'sessions'">
|
||||
<WebHookSessions
|
||||
|
||||
:key="selectedWebHook"
|
||||
:webHook="selectedWebHook"></WebHookSessions>
|
||||
<template #fallback>
|
||||
<div class="p-3">
|
||||
<LocaleText t="Loading..."></LocaleText>
|
||||
</div>
|
||||
</template>
|
||||
</Suspense>
|
||||
</div>
|
||||
</div>
|
||||
<suspense v-else>
|
||||
|
@@ -0,0 +1,143 @@
|
||||
<script setup lang="ts">
|
||||
import { fetchGet } from "@/utilities/fetch.js"
|
||||
import LocaleText from "@/components/text/localeText.vue";
|
||||
import {computed, ref, watch} from "vue";
|
||||
const props = defineProps(['webHook'])
|
||||
const sessions = ref([])
|
||||
|
||||
const refreshInterval = ref(undefined);
|
||||
|
||||
const getSessions = async () => {
|
||||
await fetchGet("/api/webHooks/getWebHookSessions", {
|
||||
WebHookID: props.webHook.WebHookID
|
||||
}, (res) => {
|
||||
sessions.value = res.data
|
||||
})
|
||||
}
|
||||
|
||||
await getSessions()
|
||||
|
||||
const latestSession = computed(() => {
|
||||
if (!sessions.value){
|
||||
return undefined
|
||||
}
|
||||
return sessions.value[0]
|
||||
})
|
||||
|
||||
watch(() => latestSession.value.Status, () => {
|
||||
if (latestSession.value.Status > -1) clearInterval(refreshInterval.value)
|
||||
})
|
||||
|
||||
|
||||
|
||||
if (latestSession.value.Status === -1){
|
||||
refreshInterval.value = setInterval(() => {
|
||||
getSessions()
|
||||
}, 5000)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="p-3" v-if="latestSession">
|
||||
<h6 class="mb-3">
|
||||
<LocaleText t="Latest Session"></LocaleText>
|
||||
</h6>
|
||||
<h3 :class="{'text-success': latestSession.Status === 0, 'text-danger': latestSession.Status === 1}">
|
||||
<span v-if="latestSession.Status === 0">
|
||||
<i class="bi bi-check-circle-fill me-2"></i><LocaleText t="Success"></LocaleText>
|
||||
</span>
|
||||
<span v-else-if="latestSession.Status === 1">
|
||||
<i class="bi bi-x-circle-fill me-2"></i><LocaleText t="Failed"></LocaleText>
|
||||
</span>
|
||||
<span v-else-if="latestSession.Status === -1">
|
||||
<i class="spinner-border me-2"></i><LocaleText t="Requesting..."></LocaleText>
|
||||
</span>
|
||||
</h3>
|
||||
<div class="d-flex gap-4 align-items-center">
|
||||
<div>
|
||||
<small class="text-muted">
|
||||
<LocaleText t="Started At"></LocaleText>
|
||||
</small>
|
||||
<h6>
|
||||
{{ latestSession.StartDate }}
|
||||
</h6>
|
||||
</div>
|
||||
<div v-if="latestSession.EndDate">
|
||||
<i class="bi bi-arrow-right"></i>
|
||||
</div>
|
||||
<div v-if="latestSession.EndDate">
|
||||
<small class="text-muted">
|
||||
<LocaleText t="Ended At"></LocaleText>
|
||||
</small>
|
||||
<h6>
|
||||
{{ latestSession.EndDate }}
|
||||
</h6>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div>
|
||||
<h6>
|
||||
<LocaleText t="Logs"></LocaleText>
|
||||
</h6>
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">
|
||||
<LocaleText t="Datetime"></LocaleText>
|
||||
</th>
|
||||
<th scope="col">
|
||||
<LocaleText t="Status"></LocaleText>
|
||||
</th>
|
||||
<th scope="col">
|
||||
<LocaleText t="Message"></LocaleText>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="log in [...latestSession.Logs.Logs].reverse()">
|
||||
<td style="white-space: nowrap">
|
||||
{{ log.LogTime }}
|
||||
</td>
|
||||
<td style="white-space: nowrap" :class="{'text-success': log.Status === 0, 'text-danger': log.Status === 1}">
|
||||
<span v-if="log.Status === 0">
|
||||
<i class="bi bi-check-circle-fill me-2"></i>
|
||||
</span>
|
||||
<span v-else-if="log.Status === 1">
|
||||
<i class="bi bi-x-circle-fill me-2"></i>
|
||||
</span>
|
||||
<span v-else-if="log.Status === -1">
|
||||
<i class="bi bi-circle me-2"></i>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
{{ log.Message }}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h6>
|
||||
<LocaleText t="Data"></LocaleText>
|
||||
</h6>
|
||||
<div class="bg-body-tertiary p-3 rounded-3" style="max-height: 200px; overflow: scroll">
|
||||
<pre><code>{{ JSON.stringify(latestSession.Data, null, 4) }}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="p-3">
|
||||
<div class="bg-body-tertiary p-3 w-100 d-flex rounded-3" >
|
||||
<h6 class="mb-0 m-auto">No Sessions</h6>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.table > :not(caption) > * > *{
|
||||
padding-left: 0 !important;
|
||||
padding-right: 1rem !important;
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user