Files
hotline-planner/dev/backend/HotlinePlanner profile pic and bg worker/Views/Account/EventLogs.cshtml
2026-02-24 13:32:01 +01:00

139 lines
4.9 KiB
Plaintext

@{
ViewData["Title"] = "Event Logs";
}
<div class="animate__animated animate__fadeIn">
<div class="row items-center q-mb-lg">
<div class="col">
<h1 class="text-h4 text-weight-bold text-primary q-ma-none">System Audit Logs</h1>
<div class="text-subtitle2 text-grey-6 uppercase q-mt-xs" style="letter-spacing: 1px">Internal Activity Tracking</div>
</div>
<div class="col-auto">
<q-btn flat round color="primary" icon="refresh" v-on:click="onRequest({ pagination })">
<q-tooltip>Refresh Data</q-tooltip>
</q-btn>
</div>
</div>
<q-card flat class="clean-card overflow-hidden">
<q-table
:rows="rows"
:columns="columns"
row-key="id"
v-model:pagination="pagination"
:loading="loading"
:filter="filter"
binary-state-sort
v-on:request="onRequest"
flat
bordered
class="no-shadow"
:rows-per-page-options="[10, 20, 50, 100]"
>
<template v-slot:top-right>
<q-input borderless dense debounce="300" v-model="filter" placeholder="Search logs...">
<template v-slot:append>
<q-icon name="search"></q-icon>
</template>
</q-input>
</template>
<template v-slot:body-cell-level="props">
<q-td :props="props">
<q-badge :color="getLevelColor(props.value)" rounded>
{{ props.value }}
</q-badge>
</q-td>
</template>
<template v-slot:body-cell-timestamp="props">
<q-td :props="props">
{{ formatDate(props.value) }}
</q-td>
</template>
</q-table>
</q-card>
</div>
<style>
.uppercase { text-transform: uppercase; font-size: 0.7rem; }
.clean-card { border-radius: 12px; }
</style>
@section Scripts {
<script>
app.mixin({
data() {
return {
filter: '',
loading: false,
pagination: {
sortBy: 'timestamp',
descending: true,
page: 1,
rowsPerPage: 10,
rowsNumber: 0
},
columns: [
{ name: 'timestamp', label: 'Timestamp (UTC)', field: 'timestamp', align: 'left', sortable: true },
{ name: 'level', label: 'Level', field: 'level', align: 'center', sortable: true },
{ name: 'category', label: 'Category', field: 'category', align: 'left', sortable: true },
{ name: 'message', label: 'Message', field: 'message', align: 'left', sortable: false },
{ name: 'userId', label: 'User ID', field: 'userId', align: 'left', sortable: true }
],
rows: []
}
},
mounted() {
this.onRequest({
pagination: this.pagination,
filter: this.filter
});
},
methods: {
async onRequest(props) {
const { page, rowsPerPage, sortBy, descending } = props.pagination;
const filter = props.filter;
this.loading = true;
try {
const url = `/Account/GetEventLogsData?page=${page}&rowsPerPage=${rowsPerPage}&filter=${filter || ''}`;
const response = await fetch(url);
const data = await response.json();
this.rows = data.items;
this.pagination.rowsNumber = data.totalItems;
this.pagination.page = page;
this.pagination.rowsPerPage = rowsPerPage;
this.pagination.sortBy = sortBy;
this.pagination.descending = descending;
} catch (error) {
console.error('Fetch error:', error);
this.$q.notify({
color: 'negative',
message: 'Failed to load logs',
icon: 'report_problem'
});
} finally {
this.loading = false;
}
},
getLevelColor(level) {
switch (level?.toLowerCase()) {
case 'info': return 'blue-6';
case 'warning': return 'orange-8';
case 'error': return 'negative';
default: return 'grey-6';
}
},
formatDate(val) {
if (!val) return '—';
const date = new Date(val);
return date.toLocaleString();
}
}
});
</script>
}