mirror of
https://github.com/jpros/tacticalrmm-web.git
synced 2026-01-20 03:50:21 +00:00
finish debug and audit rework
This commit is contained in:
@@ -1,160 +0,0 @@
|
||||
<template>
|
||||
<q-card>
|
||||
<q-bar>
|
||||
<q-btn @click="search" class="q-mr-sm" dense flat push icon="refresh" />
|
||||
<q-space />Audit Manager
|
||||
<q-space />
|
||||
<q-btn dense flat icon="close" v-close-popup>
|
||||
<q-tooltip class="bg-white text-primary">Close</q-tooltip>
|
||||
</q-btn>
|
||||
</q-bar>
|
||||
<div class="text-h6 q-pl-sm q-pt-sm">Filter</div>
|
||||
<div class="row">
|
||||
<div class="q-pa-sm col-1">
|
||||
<q-option-group v-model="filterType" :options="filterTypeOptions" color="primary" />
|
||||
</div>
|
||||
<div class="q-pa-sm col-2" v-if="filterType === 'agents'">
|
||||
<tactical-dropdown v-model="agentFilter" :options="agentOptions" label="Agent" clearable multiple filled />
|
||||
</div>
|
||||
<div class="q-pa-sm col-2" v-if="filterType === 'clients'">
|
||||
<tactical-dropdown
|
||||
v-model="clientFilter"
|
||||
:options="clientOptions"
|
||||
label="Clients"
|
||||
clearable
|
||||
multiple
|
||||
filled
|
||||
mapOptions
|
||||
/>
|
||||
</div>
|
||||
<div class="q-pa-sm col-2">
|
||||
<tactical-dropdown v-model="userFilter" :options="userOptions" label="Users" clearable filled multiple />
|
||||
</div>
|
||||
<div class="q-pa-sm col-2">
|
||||
<tactical-dropdown
|
||||
v-model="actionFilter"
|
||||
:options="actionOptions"
|
||||
label="Action"
|
||||
clearable
|
||||
filled
|
||||
multiple
|
||||
mapOptions
|
||||
/>
|
||||
</div>
|
||||
<div class="q-pa-sm col-2">
|
||||
<tactical-dropdown
|
||||
v-model="objectFilter"
|
||||
:options="objectOptions"
|
||||
label="Object"
|
||||
clearable
|
||||
filled
|
||||
multiple
|
||||
mapOptions
|
||||
/>
|
||||
</div>
|
||||
<div class="q-pa-sm col-2">
|
||||
<tactical-dropdown v-model="timeFilter" :options="timeOptions" label="Time" filled mapOptions />
|
||||
</div>
|
||||
<div class="q-pa-sm col-1">
|
||||
<q-btn color="primary" label="Search" @click="search" />
|
||||
</div>
|
||||
</div>
|
||||
<q-separator />
|
||||
<q-card-section>
|
||||
<q-table
|
||||
@request="onRequest"
|
||||
title="Audit Logs"
|
||||
:rows="auditLogs"
|
||||
:columns="columns"
|
||||
row-key="id"
|
||||
dense
|
||||
binary-state-sort
|
||||
v-model:pagination="pagination"
|
||||
:rows-per-page-options="[25, 50, 100, 500, 1000]"
|
||||
:no-data-label="tableNoDataText"
|
||||
@row-click="openAuditDetail"
|
||||
:loading="loading"
|
||||
>
|
||||
<template v-slot:top-right>
|
||||
<q-btn dense color="primary" icon-right="archive" @click="exportLog" />
|
||||
</template>
|
||||
<template v-slot:body-cell-action="props">
|
||||
<q-td :props="props">
|
||||
<div>
|
||||
<q-badge :color="formatActionColor(props.value)" :label="props.value" />
|
||||
</div>
|
||||
</q-td>
|
||||
</template>
|
||||
</q-table>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// composition imports
|
||||
import { onMounted } from "vue";
|
||||
import { useAuditLog } from "@/composables/logs";
|
||||
import { useClientDropdown } from "@/composables/clients";
|
||||
import { useAgentDropdown } from "@/composables/agents";
|
||||
import { useUserDropdown } from "@/composables/accounts";
|
||||
import { exportTableToCSV } from "@/utils/csv";
|
||||
|
||||
// ui imported
|
||||
import TacticalDropdown from "@/components/ui/TacticalDropdown";
|
||||
|
||||
export default {
|
||||
name: "AuditManager",
|
||||
components: { TacticalDropdown },
|
||||
setup() {
|
||||
// setup dropdowns
|
||||
const { clientOptions, getClientOptions } = useClientDropdown();
|
||||
const { agentOptions, getAgentOptions } = useAgentDropdown();
|
||||
const { userOptions, userDropdownLoading, getUserOptions } = useUserDropdown();
|
||||
|
||||
onMounted(() => {
|
||||
getClientOptions();
|
||||
getAgentOptions(true);
|
||||
getUserOptions(true);
|
||||
});
|
||||
|
||||
const AuditLog = useAuditLog();
|
||||
|
||||
return {
|
||||
// data
|
||||
auditLogs: AuditLog.auditLogs,
|
||||
agentFilter: AuditLog.agentFilter,
|
||||
userFilter: AuditLog.userFilter,
|
||||
actionFilter: AuditLog.actionFilter,
|
||||
clientFilter: AuditLog.clientFilter,
|
||||
objectFilter: AuditLog.objectFilter,
|
||||
timeFilter: AuditLog.timeFilter,
|
||||
filterType: AuditLog.filterType,
|
||||
loading: AuditLog.loading,
|
||||
pagination: AuditLog.pagination,
|
||||
userOptions,
|
||||
userDropdownLoading,
|
||||
|
||||
// non-reactive data
|
||||
clientOptions,
|
||||
agentOptions,
|
||||
columns: useAuditLog.tableColumns,
|
||||
actionOptions: useAuditLog.actionOptions,
|
||||
objectOptions: useAuditLog.objectOptions,
|
||||
timeOptions: useAuditLog.timeOptions,
|
||||
filterTypeOptions: useAuditLog.filterTypeOptions,
|
||||
|
||||
//computed
|
||||
tableNoDataText: AuditLog.noDataText,
|
||||
|
||||
// methods
|
||||
search: AuditLog.search,
|
||||
onRequest: AuditLog.onRequest,
|
||||
openAuditDetail: AuditLog.openAuditDetail,
|
||||
formatActionColor: AuditLog.formatActionColor,
|
||||
exportLog: () => {
|
||||
exportTableToCSV(auditLogs, useAuditLog.tableColumns);
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -25,10 +25,10 @@
|
||||
<q-item clickable v-close-popup @click="showUploadMesh = true">
|
||||
<q-item-section>Upload MeshAgent</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable v-close-popup @click="showAuditManager = true">
|
||||
<q-item clickable v-close-popup @click="showAuditManager">
|
||||
<q-item-section>Audit Log</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable v-close-popup @click="showDebugLog()">
|
||||
<q-item clickable v-close-popup @click="showDebugLog">
|
||||
<q-item-section>Debug Log</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
@@ -154,12 +154,6 @@
|
||||
<PendingActions @close="showPendingActions = false" />
|
||||
</q-dialog>
|
||||
</div>
|
||||
<!-- audit manager -->
|
||||
<div class="q-pa-md q-gutter-sm">
|
||||
<q-dialog v-model="showAuditManager" maximized transition-show="slide-up" transition-hide="slide-down">
|
||||
<AuditManager @close="showAuditManager = false" />
|
||||
</q-dialog>
|
||||
</div>
|
||||
<!-- Install Agents -->
|
||||
<div class="q-pa-md q-gutter-sm">
|
||||
<q-dialog v-model="showInstallAgent">
|
||||
@@ -223,7 +217,7 @@ import AutomationManager from "@/components/automation/AutomationManager";
|
||||
import AdminManager from "@/components/AdminManager";
|
||||
import InstallAgent from "@/components/modals/agents/InstallAgent";
|
||||
import UploadMesh from "@/components/modals/core/UploadMesh";
|
||||
import AuditManager from "@/components/AuditManager";
|
||||
import AuditManager from "@/components/logs/AuditManager";
|
||||
import BulkAction from "@/components/modals/agents/BulkAction";
|
||||
import Deployment from "@/components/Deployment";
|
||||
import ServerMaintenance from "@/components/modals/core/ServerMaintenance";
|
||||
@@ -241,7 +235,6 @@ export default {
|
||||
InstallAgent,
|
||||
UploadMesh,
|
||||
AdminManager,
|
||||
AuditManager,
|
||||
BulkAction,
|
||||
Deployment,
|
||||
ServerMaintenance,
|
||||
@@ -256,7 +249,6 @@ export default {
|
||||
showAdminManager: false,
|
||||
showInstallAgent: false,
|
||||
showUploadMesh: false,
|
||||
showAuditManager: false,
|
||||
showBulkAction: false,
|
||||
showPendingActions: false,
|
||||
bulkMode: null,
|
||||
@@ -327,6 +319,23 @@ export default {
|
||||
component: PermissionsManager,
|
||||
});
|
||||
},
|
||||
showAuditManager() {
|
||||
this.$q.dialog({
|
||||
component: DialogWrapper,
|
||||
componentProps: {
|
||||
vuecomponent: AuditManager,
|
||||
noCard: true,
|
||||
componentProps: {
|
||||
modal: true,
|
||||
},
|
||||
dialogProps: {
|
||||
maximized: true,
|
||||
["transition-show"]: "slide-up",
|
||||
["transition-hide"]: "slide-down",
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
showDebugLog() {
|
||||
this.$q.dialog({
|
||||
component: DialogWrapper,
|
||||
|
||||
@@ -1,122 +1,31 @@
|
||||
<template>
|
||||
<div v-if="!selectedAgentPk">No agent selected</div>
|
||||
<div v-else class="q-pa-none">
|
||||
<div class="q-gutter-y-md">
|
||||
<q-card>
|
||||
<q-table
|
||||
@request="onRequest"
|
||||
dense
|
||||
:table-class="{ 'table-bgcolor': !$q.dark.isActive, 'table-bgcolor-dark': $q.dark.isActive }"
|
||||
class="audit-mgr-tbl-sticky"
|
||||
binary-state-sort
|
||||
title="Audit Logs"
|
||||
:rows="auditLogs"
|
||||
:columns="columns"
|
||||
row-key="id"
|
||||
v-model:pagination="pagination"
|
||||
:rows-per-page-options="[25, 50, 100, 500]"
|
||||
:no-data-label="noDataText"
|
||||
@row-click="showDetails"
|
||||
virtual-scroll
|
||||
>
|
||||
<template v-slot:top-right>
|
||||
<q-btn color="primary" icon-right="archive" label="Export to csv" no-caps @click="exportLog" />
|
||||
</template>
|
||||
<template v-slot:body-cell-action="props">
|
||||
<q-td :props="props">
|
||||
<div>
|
||||
<q-badge :color="actionColor(props.value)" :label="actionText(props.value)" />
|
||||
</div>
|
||||
</q-td>
|
||||
</template>
|
||||
</q-table>
|
||||
</q-card>
|
||||
</div>
|
||||
<div v-if="!selectedAgent">No agent selected</div>
|
||||
<div v-else>
|
||||
<AuditManager :agentpk="selectedAgent" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from "vuex";
|
||||
// composition imports
|
||||
import { computed } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
|
||||
// ui imports
|
||||
import AuditManager from "@/components/logs/AuditManager";
|
||||
|
||||
export default {
|
||||
name: "AuditTab",
|
||||
data() {
|
||||
components: {
|
||||
AuditManager,
|
||||
},
|
||||
setup() {
|
||||
const store = useStore();
|
||||
const selectedAgent = computed(() => store.state.selectedRow);
|
||||
|
||||
return {
|
||||
columns: [
|
||||
{
|
||||
name: "entry_time",
|
||||
label: "Time",
|
||||
field: "entry_time",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
format: (val, row) => this.formatDate(val, true),
|
||||
},
|
||||
{ name: "username", label: "Username", field: "username", align: "left", sortable: true },
|
||||
{ name: "action", label: "Action", field: "action", align: "left", sortable: true },
|
||||
{
|
||||
name: "object_type",
|
||||
label: "Object",
|
||||
field: "object_type",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
format: (val, row) => this.formatObject(val),
|
||||
},
|
||||
{ name: "message", label: "Message", field: "message", align: "left", sortable: true },
|
||||
],
|
||||
timeOptions: [
|
||||
{ value: 1, label: "1 Day Ago" },
|
||||
{ value: 7, label: "1 Week Ago" },
|
||||
{ value: 30, label: "30 Days Ago" },
|
||||
{ value: 90, label: "3 Months Ago" },
|
||||
{ value: 180, label: "6 Months Ago" },
|
||||
{ value: 365, label: "1 Year Ago" },
|
||||
{ value: 0, label: "Everything" },
|
||||
],
|
||||
pagination: {
|
||||
rowsPerPage: 25,
|
||||
rowsNumber: null,
|
||||
sortBy: "entry_time",
|
||||
descending: true,
|
||||
page: 1,
|
||||
},
|
||||
// computed
|
||||
selectedAgent,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(["selectedAgentPk"]),
|
||||
},
|
||||
methods: {
|
||||
onRequest(props) {
|
||||
// needed to update external pagination object
|
||||
const { page, rowsPerPage, sortBy, descending } = props.pagination;
|
||||
|
||||
this.pagination.page = page;
|
||||
this.pagination.rowsPerPage = rowsPerPage;
|
||||
this.pagination.sortBy = sortBy;
|
||||
this.pagination.descending = descending;
|
||||
|
||||
this.search();
|
||||
},
|
||||
actionColor(action) {
|
||||
if (action === "add") return "success";
|
||||
else if (action === "agent_install") return "success";
|
||||
else if (action === "modify") return "warning";
|
||||
else if (action === "delete") return "negative";
|
||||
else if (action === "failed_login") return "negative";
|
||||
else return "primary";
|
||||
},
|
||||
actionText(action) {
|
||||
if (action.includes("_")) {
|
||||
let text = action.split("_");
|
||||
return this.capitalize(text[0]) + " " + this.capitalize(text[1]);
|
||||
} else {
|
||||
return this.capitalize(action);
|
||||
}
|
||||
},
|
||||
formatObject(text) {
|
||||
if (text === "winupdatepolicy") return "Patch Policy";
|
||||
else if (text === "automatedtask") return "Automated Task";
|
||||
else if (text === "coresettings") return "Core Settings";
|
||||
else return this.capitalize(text);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<div v-if="!selectedAgent">No agent selected</div>
|
||||
<div v-else></div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// composition imports
|
||||
import { computed } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
|
||||
export default {
|
||||
name: "HistoryTab",
|
||||
setup() {
|
||||
const store = useStore();
|
||||
const selectedAgent = computed(() => store.state.selectedRow);
|
||||
|
||||
return {
|
||||
// computed
|
||||
selectedAgent,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -13,8 +13,16 @@
|
||||
<div class="q-pa-sm col-1" v-if="!agentpk">
|
||||
<q-option-group v-model="filterType" :options="filterTypeOptions" color="primary" />
|
||||
</div>
|
||||
<div class="q-pa-sm col-2" v-if="filterType === 'agents'">
|
||||
<tactical-dropdown v-model="agentFilter" :options="agentOptions" label="Agent" clearable multiple filled />
|
||||
<div class="q-pa-sm col-2" v-if="filterType === 'agents' && !agentpk">
|
||||
<tactical-dropdown
|
||||
v-model="agentFilter"
|
||||
:options="agentOptions"
|
||||
label="Agent"
|
||||
clearable
|
||||
mapOptions
|
||||
multiple
|
||||
filled
|
||||
/>
|
||||
</div>
|
||||
<div class="q-pa-sm col-2" v-if="filterType === 'clients' && !agentpk">
|
||||
<tactical-dropdown
|
||||
@@ -41,7 +49,7 @@
|
||||
mapOptions
|
||||
/>
|
||||
</div>
|
||||
<div class="q-pa-sm col-2">
|
||||
<div class="q-pa-sm col-2" v-if="!agentpk">
|
||||
<tactical-dropdown
|
||||
v-model="objectFilter"
|
||||
:options="objectOptions"
|
||||
@@ -55,11 +63,13 @@
|
||||
<div class="q-pa-sm col-2">
|
||||
<tactical-dropdown v-model="timeFilter" :options="timeOptions" label="Time" filled mapOptions />
|
||||
</div>
|
||||
<div class="q-pa-sm col-1">
|
||||
<div class="q-pa-sm col-1" v-if="!agentpk">
|
||||
<q-btn color="primary" label="Search" @click="search" />
|
||||
</div>
|
||||
<q-space />
|
||||
<export-table-btn v-if="!modal" :data="auditLogs" :columns="columns" />
|
||||
<div class="q-pa-sm" v-if="!modal">
|
||||
<export-table-btn :data="auditLogs" :columns="columns" />
|
||||
</div>
|
||||
</div>
|
||||
<q-separator />
|
||||
<q-card-section>
|
||||
@@ -94,16 +104,102 @@
|
||||
|
||||
<script>
|
||||
// composition imports
|
||||
import { onMounted } from "vue";
|
||||
import { useAuditLog } from "@/composables/logs";
|
||||
import { ref, computed, watch, onMounted, toRefs } from "vue";
|
||||
import { useClientDropdown } from "@/composables/clients";
|
||||
import { useAgentDropdown } from "@/composables/agents";
|
||||
import { useUserDropdown } from "@/composables/accounts";
|
||||
import { useQuasar } from "quasar";
|
||||
import { fetchAuditLog } from "@/api/logs";
|
||||
import { formatDate, formatTableColumnText } from "@/utils/format";
|
||||
|
||||
// ui imported
|
||||
import AuditLogDetailModal from "@/components/logs/AuditLogDetailModal";
|
||||
import ExportTableBtn from "@/components/ui/ExportTableBtn";
|
||||
import TacticalDropdown from "@/components/ui/TacticalDropdown";
|
||||
import ExportTableBtn from "../ui/ExportTableBtn.vue";
|
||||
|
||||
// static data
|
||||
const columns = [
|
||||
{
|
||||
name: "entry_time",
|
||||
label: "Time",
|
||||
field: "entry_time",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
format: (val, row) => formatDate(val, true),
|
||||
},
|
||||
{ name: "username", label: "Username", field: "username", align: "left", sortable: true },
|
||||
{ name: "agent", label: "Agent", field: "agent", align: "left", sortable: true },
|
||||
{
|
||||
name: "action",
|
||||
label: "Action",
|
||||
field: "action",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
format: (val, row) => formatTableColumnText(val),
|
||||
},
|
||||
{
|
||||
name: "object_type",
|
||||
label: "Object",
|
||||
field: "object_type",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
format: (val, row) => formatTableColumnText(val),
|
||||
},
|
||||
{ name: "message", label: "Message", field: "message", align: "left", sortable: true },
|
||||
];
|
||||
|
||||
const agentActionOptions = [
|
||||
{ value: "add", label: "Add Object" },
|
||||
{ value: "modify", label: "Modify Object" },
|
||||
{ value: "execute_command", label: "Execute Command" },
|
||||
{ value: "execute_script", label: "Execute Script" },
|
||||
{ value: "remote_session", label: "Remote Session" },
|
||||
];
|
||||
|
||||
const actionOptions = [
|
||||
{ value: "agent_install", label: "Agent Installs" },
|
||||
{ value: "bulk_action", label: "Bulk Actions" },
|
||||
{ value: "delete", label: "Delete Object" },
|
||||
{ value: "failed_login", label: "Failed User login" },
|
||||
{ value: "login", label: "User Login" },
|
||||
{ value: "modify", label: "Modify Object" },
|
||||
{ value: "task_run", label: "Task Run Results" },
|
||||
];
|
||||
|
||||
const objectOptions = [
|
||||
{ value: "agent", label: "Agent" },
|
||||
{ value: "automatedtask", label: "Automated Task" },
|
||||
{ value: "bulk", label: "Bulk Actions" },
|
||||
{ value: "coresettings", label: "Core Settings" },
|
||||
{ value: "check", label: "Check" },
|
||||
{ value: "client", label: "Client" },
|
||||
{ value: "policy", label: "Policy" },
|
||||
{ value: "site", label: "Site" },
|
||||
{ value: "script", label: "Script" },
|
||||
{ value: "user", label: "User" },
|
||||
{ value: "winupdatepolicy", label: "Patch Policy" },
|
||||
];
|
||||
|
||||
const timeOptions = [
|
||||
{ value: 1, label: "1 Day Ago" },
|
||||
{ value: 7, label: "1 Week Ago" },
|
||||
{ value: 30, label: "30 Days Ago" },
|
||||
{ value: 90, label: "3 Months Ago" },
|
||||
{ value: 180, label: "6 Months Ago" },
|
||||
{ value: 365, label: "1 Year Ago" },
|
||||
{ value: 0, label: "Everything" },
|
||||
];
|
||||
|
||||
const filterTypeOptions = [
|
||||
{
|
||||
label: "Clients",
|
||||
value: "clients",
|
||||
},
|
||||
{
|
||||
label: "Agents",
|
||||
value: "agents",
|
||||
},
|
||||
];
|
||||
|
||||
export default {
|
||||
name: "AuditManager",
|
||||
@@ -115,53 +211,143 @@ export default {
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
setup(props) {
|
||||
// setup dropdowns
|
||||
const { clientOptions, getClientOptions } = useClientDropdown();
|
||||
const { agentOptions, getAgentOptions } = useAgentDropdown();
|
||||
const { userOptions, getUserOptions } = useUserDropdown();
|
||||
|
||||
// setup main audit log functionality
|
||||
const auditLogs = ref([]);
|
||||
const agentFilter = ref(null);
|
||||
const userFilter = ref(null);
|
||||
const actionFilter = ref(null);
|
||||
const clientFilter = ref(null);
|
||||
const objectFilter = ref(null);
|
||||
const timeFilter = ref(7);
|
||||
const filterType = ref("clients");
|
||||
const loading = ref(false);
|
||||
const searched = ref(false);
|
||||
|
||||
const pagination = ref({
|
||||
rowsPerPage: 25,
|
||||
rowsNumber: null,
|
||||
sortBy: "entry_time",
|
||||
descending: true,
|
||||
page: 1,
|
||||
});
|
||||
|
||||
async function search() {
|
||||
loading.value = true;
|
||||
searched.value = true;
|
||||
|
||||
const data = {
|
||||
pagination: pagination.value,
|
||||
};
|
||||
|
||||
if (agentFilter.value && agentFilter.value.length > 0) data["agentFilter"] = agentFilter.value;
|
||||
else if (clientFilter.value && clientFilter.value.length > 0) data["clientFilter"] = clientFilter.value;
|
||||
if (userFilter.value && userFilter.value.length > 0) data["userFilter"] = userFilter.value;
|
||||
if (timeFilter.value) data["timeFilter"] = timeFilter.value;
|
||||
if (actionFilter.value && actionFilter.value.length > 0) data["actionFilter"] = actionFilter.value;
|
||||
if (objectFilter.value && objectFilter.value.length > 0) data["objectFilter"] = objectFilter.value;
|
||||
|
||||
console.log(data);
|
||||
const { audit_logs, total } = await fetchAuditLog(data);
|
||||
auditLogs.value = audit_logs;
|
||||
pagination.value.rowsNumber = total;
|
||||
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
function onRequest(data) {
|
||||
const { page, rowsPerPage, sortBy, descending } = data.pagination;
|
||||
|
||||
pagination.value.page = page;
|
||||
pagination.value.rowsPerPage = rowsPerPage;
|
||||
pagination.value.sortBy = sortBy;
|
||||
pagination.value.descending = descending;
|
||||
|
||||
search();
|
||||
}
|
||||
|
||||
// audit detail modal
|
||||
const { dialog } = useQuasar();
|
||||
function openAuditDetail(evt, log) {
|
||||
dialog({
|
||||
component: AuditLogDetailModal,
|
||||
componentProps: {
|
||||
log,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function formatActionColor(action) {
|
||||
if (action === "add") return "success";
|
||||
else if (action === "agent_install") return "success";
|
||||
else if (action === "modify") return "warning";
|
||||
else if (action === "delete") return "negative";
|
||||
else if (action === "failed_login") return "negative";
|
||||
else return "primary";
|
||||
}
|
||||
|
||||
// watchers
|
||||
watch(filterType, () => {
|
||||
agentFilter.value = null;
|
||||
clientFilter.value = null;
|
||||
});
|
||||
|
||||
if (props.agentpk) {
|
||||
agentFilter.value = [props.agentpk];
|
||||
watch([userFilter, actionFilter, timeFilter], search);
|
||||
}
|
||||
|
||||
// vue component hooks
|
||||
onMounted(() => {
|
||||
if (!props.agentpk) {
|
||||
getClientOptions();
|
||||
getAgentOptions();
|
||||
} else {
|
||||
search();
|
||||
}
|
||||
|
||||
getUserOptions(true);
|
||||
});
|
||||
|
||||
const AuditLog = useAuditLog();
|
||||
|
||||
return {
|
||||
// data
|
||||
auditLogs: AuditLog.auditLogs,
|
||||
agentFilter: agentpk ? [agentpk] : AuditLog.agentFilter,
|
||||
userFilter: AuditLog.userFilter,
|
||||
actionFilter: AuditLog.actionFilter,
|
||||
clientFilter: AuditLog.clientFilter,
|
||||
objectFilter: AuditLog.objectFilter,
|
||||
timeFilter: AuditLog.timeFilter,
|
||||
filterType: AuditLog.filterType,
|
||||
loading: AuditLog.loading,
|
||||
pagination: AuditLog.pagination,
|
||||
auditLogs,
|
||||
agentFilter,
|
||||
userFilter,
|
||||
actionFilter,
|
||||
clientFilter,
|
||||
objectFilter,
|
||||
timeFilter,
|
||||
filterType,
|
||||
loading,
|
||||
searched,
|
||||
pagination,
|
||||
userOptions,
|
||||
|
||||
// non-reactive data
|
||||
clientOptions,
|
||||
agentOptions,
|
||||
columns: useAuditLog.tableColumns,
|
||||
actionOptions: useAuditLog.actionOptions,
|
||||
objectOptions: useAuditLog.objectOptions,
|
||||
timeOptions: useAuditLog.timeOptions,
|
||||
filterTypeOptions: useAuditLog.filterTypeOptions,
|
||||
columns,
|
||||
actionOptions: props.agentpk ? [...agentActionOptions] : [...agentActionOptions, ...actionOptions],
|
||||
objectOptions,
|
||||
timeOptions,
|
||||
filterTypeOptions,
|
||||
|
||||
//computed
|
||||
tableNoDataText: AuditLog.noDataText,
|
||||
tableNoDataText: computed(() =>
|
||||
searched.value ? "No data found. Try to refine you search" : "Click search to find audit logs"
|
||||
),
|
||||
|
||||
// methods
|
||||
search: AuditLog.search,
|
||||
onRequest: AuditLog.onRequest,
|
||||
openAuditDetail: AuditLog.openAuditDetail,
|
||||
formatActionColor: AuditLog.formatActionColor,
|
||||
search,
|
||||
onRequest,
|
||||
openAuditDetail,
|
||||
formatActionColor,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
:columns="columns"
|
||||
:title="modal ? 'Debug Logs' : ''"
|
||||
:pagination="{ sortBy: 'entry_time', descending: true }"
|
||||
:loading="loading"
|
||||
dense
|
||||
binary-state-sort
|
||||
>
|
||||
@@ -55,14 +56,46 @@
|
||||
|
||||
<script>
|
||||
// composition api
|
||||
import { watch, onMounted } from "vue";
|
||||
import { useDebugLog } from "@/composables/logs";
|
||||
import { ref, watch, onMounted, toRefs } from "vue";
|
||||
import { useAgentDropdown } from "@/composables/agents";
|
||||
import { fetchDebugLog } from "@/api/logs";
|
||||
import { formatDate, formatTableColumnText } from "@/utils/format";
|
||||
|
||||
// ui components
|
||||
import TacticalDropdown from "@/components/ui/TacticalDropdown";
|
||||
import ExportTableBtn from "@/components/ui/ExportTableBtn.vue";
|
||||
|
||||
// static data
|
||||
const logTypeOptions = [
|
||||
{ label: "Agent Update", value: "agent_update" },
|
||||
{ label: "Agent Issues", value: "agent_issues" },
|
||||
{ label: "Windows Updates", value: "windows_updates" },
|
||||
{ label: "System Issues", value: "system_issues" },
|
||||
{ label: "Scripting", value: "scripting" },
|
||||
];
|
||||
|
||||
const columns = [
|
||||
{
|
||||
name: "entry_time",
|
||||
label: "Time",
|
||||
field: "entry_time",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
format: (val, row) => formatDate(val, true),
|
||||
},
|
||||
{ name: "log_level", label: "Log Level", field: "log_level", align: "left", sortable: true },
|
||||
{ name: "agent", label: "Agent", field: "agent", align: "left", sortable: true },
|
||||
{
|
||||
name: "log_type",
|
||||
label: "Log Type",
|
||||
field: "log_type",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
format: (val, row) => formatTableColumnText(val),
|
||||
},
|
||||
{ name: "message", label: "Message", field: "message", align: "left", sortable: true },
|
||||
];
|
||||
|
||||
export default {
|
||||
name: "LogModal",
|
||||
components: {
|
||||
@@ -77,15 +110,36 @@ export default {
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { debugLog, logLevelFilter, logTypeFilter, agentFilter, getDebugLog } = useDebugLog();
|
||||
// setup dropdowns
|
||||
const { agentOptions, getAgentOptions } = useAgentDropdown();
|
||||
|
||||
// set main debug log functionality
|
||||
const debugLog = ref([]);
|
||||
const agentFilter = ref(null);
|
||||
const logLevelFilter = ref("info");
|
||||
const logTypeFilter = ref(null);
|
||||
const loading = ref(false);
|
||||
|
||||
async function getDebugLog() {
|
||||
loading.value = true;
|
||||
const data = {
|
||||
logLevelFilter: logLevelFilter.value,
|
||||
};
|
||||
if (agentFilter.value) data["agentFilter"] = agentFilter.value;
|
||||
if (logTypeFilter.value) data["logTypeFilter"] = logTypeFilter.value;
|
||||
|
||||
debugLog.value = await fetchDebugLog(data);
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
if (props.agentpk) {
|
||||
agentFilter.value = props.agentpk;
|
||||
}
|
||||
|
||||
// watchers
|
||||
watch([logLevelFilter, agentFilter, logTypeFilter], getDebugLog);
|
||||
|
||||
// vue component hooks
|
||||
onMounted(() => {
|
||||
if (!props.agentpk) getAgentOptions();
|
||||
getDebugLog();
|
||||
@@ -98,10 +152,11 @@ export default {
|
||||
logTypeFilter,
|
||||
agentFilter,
|
||||
agentOptions,
|
||||
loading,
|
||||
|
||||
// non-reactive data
|
||||
columns: useDebugLog.tableColumns,
|
||||
logTypeOptions: useDebugLog.logTypeOptions,
|
||||
columns,
|
||||
logTypeOptions,
|
||||
|
||||
// methods
|
||||
getDebugLog,
|
||||
|
||||
@@ -3,6 +3,7 @@ import { ref } from "vue"
|
||||
import { fetchAgents } from "@/api/agents"
|
||||
import { formatAgentOptions } from "@/utils/format"
|
||||
|
||||
// agent dropdown
|
||||
export function useAgentDropdown() {
|
||||
|
||||
const agentOptions = ref([])
|
||||
@@ -19,4 +20,4 @@ export function useAgentDropdown() {
|
||||
//methods
|
||||
getAgentOptions
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,250 +0,0 @@
|
||||
import { ref, computed, watch } from "vue"
|
||||
import { useQuasar } from "quasar"
|
||||
import { fetchDebugLog, fetchAuditLog } from "@/api/logs"
|
||||
import { formatDate, formatTableColumnText } from "@/utils/format"
|
||||
import AuditLogDetailModal from "@/components/logs/AuditLogDetailModal";
|
||||
|
||||
// debug log
|
||||
export function useDebugLog() {
|
||||
|
||||
const debugLog = ref([])
|
||||
const agentFilter = ref(null)
|
||||
const logLevelFilter = ref("info")
|
||||
const logTypeFilter = ref(null)
|
||||
|
||||
async function getDebugLog() {
|
||||
const data = {
|
||||
logLevelFilter: logLevelFilter.value
|
||||
}
|
||||
if (agentFilter.value) data["agentFilter"] = agentFilter.value
|
||||
if (logTypeFilter.value) data["logTypeFilter"] = logTypeFilter.value
|
||||
|
||||
debugLog.value = await fetchDebugLog(data)
|
||||
}
|
||||
|
||||
return {
|
||||
// data
|
||||
logLevelFilter,
|
||||
logTypeFilter,
|
||||
agentFilter,
|
||||
debugLog,
|
||||
|
||||
// methods
|
||||
getDebugLog
|
||||
}
|
||||
}
|
||||
|
||||
useDebugLog.logTypeOptions = [
|
||||
{ label: "Agent Update", value: "agent_update" },
|
||||
{ label: "Agent Issues", value: "agent_issues" },
|
||||
{ label: "Windows Updates", value: "windows_updates" },
|
||||
{ label: "System Issues", value: "system_issues" },
|
||||
{ label: "Scripting", value: "scripting" }
|
||||
]
|
||||
|
||||
useDebugLog.tableColumns = [
|
||||
{
|
||||
name: "entry_time",
|
||||
label: "Time",
|
||||
field: "entry_time",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
format: (val, row) => formatDate(val, true),
|
||||
},
|
||||
{ name: "log_level", label: "Log Level", field: "log_level", align: "left", sortable: true },
|
||||
{ name: "agent", label: "Agent", field: "agent", align: "left", sortable: true },
|
||||
{
|
||||
name: "log_type",
|
||||
label: "Log Type",
|
||||
field: "log_type",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
format: (val, row) => formatTableColumnText(val),
|
||||
},
|
||||
{ name: "message", label: "Message", field: "message", align: "left", sortable: true },
|
||||
]
|
||||
|
||||
// audit Log
|
||||
export function useAuditLog() {
|
||||
const auditLogs = ref([])
|
||||
const agentFilter = ref(null)
|
||||
const userFilter = ref(null)
|
||||
const actionFilter = ref(null)
|
||||
const clientFilter = ref(null)
|
||||
const objectFilter = ref(null)
|
||||
const timeFilter = ref(7)
|
||||
const filterType = ref("clients")
|
||||
const loading = ref(false)
|
||||
const searched = ref(false)
|
||||
|
||||
const pagination = ref({
|
||||
rowsPerPage: 25,
|
||||
rowsNumber: null,
|
||||
sortBy: "entry_time",
|
||||
descending: true,
|
||||
page: 1,
|
||||
})
|
||||
|
||||
async function search() {
|
||||
loading.value = true
|
||||
searched.value = true;
|
||||
|
||||
const data = {
|
||||
pagination: pagination.value
|
||||
};
|
||||
|
||||
if (!!agentFilter.value && agentFilter.value.length > 0) data["agentFilter"] = agentFilter.value;
|
||||
else if (!!clientFilter.value && clientFilter.value.length > 0) data["clientFilter"] = clientFilter.value;
|
||||
if (!!userFilter.value && userFilter.value.length > 0) data["userFilter"] = userFilter.value;
|
||||
if (!!timeFilter.value) data["timeFilter"] = timeFilter.value;
|
||||
if (!!actionFilter.value && actionFilter.value.length > 0) data["actionFilter"] = actionFilter.value;
|
||||
if (!!objectFilter.value && objectFilter.value.length > 0) data["objectFilter"] = objectFilter.value;
|
||||
|
||||
const { audit_logs, total } = await fetchAuditLog(data)
|
||||
auditLogs.value = audit_logs
|
||||
pagination.value.rowsNumber = total
|
||||
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
function onRequest(props) {
|
||||
const { page, rowsPerPage, sortBy, descending } = props.pagination;
|
||||
|
||||
pagination.value.page = page;
|
||||
pagination.value.rowsPerPage = rowsPerPage;
|
||||
pagination.value.sortBy = sortBy;
|
||||
pagination.value.descending = descending;
|
||||
|
||||
search();
|
||||
}
|
||||
|
||||
const { dialog } = useQuasar()
|
||||
function openAuditDetail(evt, log) {
|
||||
dialog({
|
||||
component: AuditLogDetailModal,
|
||||
componentProps: {
|
||||
log
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function formatActionColor(action) {
|
||||
if (action === "add") return "success";
|
||||
else if (action === "agent_install") return "success";
|
||||
else if (action === "modify") return "warning";
|
||||
else if (action === "delete") return "negative";
|
||||
else if (action === "failed_login") return "negative";
|
||||
else return "primary";
|
||||
}
|
||||
|
||||
watch(filterType, () => {
|
||||
agentFilter.value = null
|
||||
clientFilter.value = null
|
||||
})
|
||||
|
||||
const noDataText = computed(() => searched ? "No data found. Try to refine you search" : "Click search to find audit logs")
|
||||
|
||||
return {
|
||||
// data
|
||||
auditLogs,
|
||||
agentFilter,
|
||||
userFilter,
|
||||
actionFilter,
|
||||
clientFilter,
|
||||
objectFilter,
|
||||
timeFilter,
|
||||
filterType,
|
||||
loading,
|
||||
searched,
|
||||
pagination,
|
||||
|
||||
//computed
|
||||
noDataText,
|
||||
|
||||
// methods
|
||||
search,
|
||||
onRequest,
|
||||
openAuditDetail,
|
||||
formatActionColor
|
||||
}
|
||||
}
|
||||
|
||||
useAuditLog.tableColumns = [
|
||||
{
|
||||
name: "entry_time",
|
||||
label: "Time",
|
||||
field: "entry_time",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
format: (val, row) => formatDate(val, true),
|
||||
},
|
||||
{ name: "username", label: "Username", field: "username", align: "left", sortable: true },
|
||||
{ name: "agent", label: "Agent", field: "agent", align: "left", sortable: true },
|
||||
{
|
||||
name: "action",
|
||||
label: "Action",
|
||||
field: "action",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
format: (val, row) => formatTableColumnText(val)
|
||||
},
|
||||
{
|
||||
name: "object_type",
|
||||
label: "Object",
|
||||
field: "object_type",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
format: (val, row) => formatTableColumnText(val),
|
||||
},
|
||||
{ name: "message", label: "Message", field: "message", align: "left", sortable: true },
|
||||
]
|
||||
|
||||
useAuditLog.actionOptions = [
|
||||
{ value: "agent_install", label: "Agent Installs" },
|
||||
{ value: "add", label: "Add Object" },
|
||||
{ value: "bulk_action", label: "Bulk Actions" },
|
||||
{ value: "check_run", label: "Check Run Results" },
|
||||
{ value: "execute_command", label: "Execute Command" },
|
||||
{ value: "execute_script", label: "Execute Script" },
|
||||
{ value: "delete", label: "Delete Object" },
|
||||
{ value: "failed_login", label: "Failed User login" },
|
||||
{ value: "login", label: "User Login" },
|
||||
{ value: "modify", label: "Modify Object" },
|
||||
{ value: "remote_session", label: "Remote Session" },
|
||||
{ value: "task_run", label: "Task Run Results" },
|
||||
]
|
||||
|
||||
useAuditLog.objectOptions = [
|
||||
{ value: "agent", label: "Agent" },
|
||||
{ value: "automatedtask", label: "Automated Task" },
|
||||
{ value: "bulk", label: "Bulk Actions" },
|
||||
{ value: "coresettings", label: "Core Settings" },
|
||||
{ value: "check", label: "Check" },
|
||||
{ value: "client", label: "Client" },
|
||||
{ value: "policy", label: "Policy" },
|
||||
{ value: "site", label: "Site" },
|
||||
{ value: "script", label: "Script" },
|
||||
{ value: "user", label: "User" },
|
||||
{ value: "winupdatepolicy", label: "Patch Policy" },
|
||||
]
|
||||
|
||||
useAuditLog.timeOptions = [
|
||||
{ value: 1, label: "1 Day Ago" },
|
||||
{ value: 7, label: "1 Week Ago" },
|
||||
{ value: 30, label: "30 Days Ago" },
|
||||
{ value: 90, label: "3 Months Ago" },
|
||||
{ value: 180, label: "6 Months Ago" },
|
||||
{ value: 365, label: "1 Year Ago" },
|
||||
{ value: 0, label: "Everything" },
|
||||
]
|
||||
|
||||
useAuditLog.filterTypeOptions = [
|
||||
{
|
||||
label: "Clients",
|
||||
value: "clients",
|
||||
},
|
||||
{
|
||||
label: "Agents",
|
||||
value: "agents",
|
||||
},
|
||||
]
|
||||
Reference in New Issue
Block a user