fix search/sort
This commit is contained in:
parent
3e276fc2ac
commit
129c50e598
|
@ -54,66 +54,22 @@ class TestAgentsList(TacticalTestCase):
|
|||
_quantity=7,
|
||||
)
|
||||
|
||||
data = {
|
||||
"pagination": {
|
||||
"rowsPerPage": 50,
|
||||
"rowsNumber": None,
|
||||
"sortBy": "hostname",
|
||||
"descending": False,
|
||||
"page": 1,
|
||||
},
|
||||
"monType": "mixed",
|
||||
}
|
||||
# test all agents
|
||||
r = self.client.patch(url, format="json")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(len(r.data), 36) # type: ignore
|
||||
|
||||
# test mixed
|
||||
# test client1
|
||||
data = {"clientPK": company1.pk} # type: ignore
|
||||
r = self.client.patch(url, data, format="json")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.data["total"], 36) # type: ignore
|
||||
self.assertEqual(len(r.data["agents"]), 36) # type: ignore
|
||||
self.assertEqual(len(r.data), 25) # type: ignore
|
||||
|
||||
# test servers
|
||||
data["monType"] = "server"
|
||||
data["pagination"]["rowsPerPage"] = 6
|
||||
# test site3
|
||||
data = {"sitePK": site3.pk} # type: ignore
|
||||
r = self.client.patch(url, data, format="json")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.data["total"], 19) # type: ignore
|
||||
self.assertEqual(len(r.data["agents"]), 6) # type: ignore
|
||||
|
||||
# test workstations
|
||||
data["monType"] = "server"
|
||||
data["pagination"]["rowsPerPage"] = 6
|
||||
r = self.client.patch(url, data, format="json")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.data["total"], 19) # type: ignore
|
||||
self.assertEqual(len(r.data["agents"]), 6) # type: ignore
|
||||
|
||||
# test client1 mixed
|
||||
data = {
|
||||
"pagination": {
|
||||
"rowsPerPage": 3,
|
||||
"rowsNumber": None,
|
||||
"sortBy": "hostname",
|
||||
"descending": False,
|
||||
"page": 1,
|
||||
},
|
||||
"monType": "mixed",
|
||||
"clientPK": company1.pk, # type: ignore
|
||||
}
|
||||
|
||||
r = self.client.patch(url, data, format="json")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.data["total"], 25) # type: ignore
|
||||
self.assertEqual(len(r.data["agents"]), 3) # type: ignore
|
||||
|
||||
# test site3 workstations
|
||||
del data["clientPK"]
|
||||
data["monType"] = "workstation"
|
||||
data["sitePK"] = site3.pk # type: ignore
|
||||
|
||||
r = self.client.patch(url, data, format="json")
|
||||
self.assertEqual(r.status_code, 200)
|
||||
self.assertEqual(r.data["total"], 7) # type: ignore
|
||||
self.assertEqual(len(r.data["agents"]), 3) # type: ignore
|
||||
self.assertEqual(len(r.data), 11) # type: ignore
|
||||
|
||||
self.check_not_authenticated("patch", url)
|
||||
|
||||
|
|
|
@ -5,8 +5,6 @@ import random
|
|||
import string
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.paginator import Paginator
|
||||
from django.db.models import Q
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from loguru import logger
|
||||
|
@ -228,72 +226,45 @@ def send_raw_cmd(request):
|
|||
|
||||
class AgentsTableList(APIView):
|
||||
def patch(self, request):
|
||||
pagination = request.data["pagination"]
|
||||
monType = request.data["monType"]
|
||||
client = Q()
|
||||
site = Q()
|
||||
mon_type = Q()
|
||||
|
||||
if pagination["sortBy"] == "agentstatus":
|
||||
sort = "last_seen"
|
||||
elif pagination["sortBy"] == "client_name":
|
||||
sort = "site__client__name"
|
||||
elif pagination["sortBy"] == "site_name":
|
||||
sort = "site__name"
|
||||
elif pagination["sortBy"] == "user":
|
||||
sort = "logged_in_username"
|
||||
else:
|
||||
sort = pagination["sortBy"]
|
||||
|
||||
order_by = f"-{sort}" if pagination["descending"] else sort
|
||||
|
||||
if monType == "server":
|
||||
mon_type = Q(monitoring_type="server")
|
||||
elif monType == "workstation":
|
||||
mon_type = Q(monitoring_type="workstation")
|
||||
|
||||
if "clientPK" in request.data:
|
||||
client = Q(site__client_id=request.data["clientPK"])
|
||||
|
||||
if "sitePK" in request.data:
|
||||
site = Q(site_id=request.data["sitePK"])
|
||||
|
||||
queryset = (
|
||||
Agent.objects.select_related("site")
|
||||
.prefetch_related("agentchecks")
|
||||
.filter(mon_type)
|
||||
.filter(client)
|
||||
.filter(site)
|
||||
.only(
|
||||
"pk",
|
||||
"hostname",
|
||||
"agent_id",
|
||||
"site",
|
||||
"monitoring_type",
|
||||
"description",
|
||||
"needs_reboot",
|
||||
"overdue_text_alert",
|
||||
"overdue_email_alert",
|
||||
"overdue_time",
|
||||
"offline_time",
|
||||
"last_seen",
|
||||
"boot_time",
|
||||
"logged_in_username",
|
||||
"last_logged_in_user",
|
||||
"time_zone",
|
||||
"maintenance_mode",
|
||||
if "sitePK" in request.data.keys():
|
||||
queryset = (
|
||||
Agent.objects.select_related("site")
|
||||
.prefetch_related("agentchecks")
|
||||
.filter(site_id=request.data["sitePK"])
|
||||
)
|
||||
elif "clientPK" in request.data.keys():
|
||||
queryset = (
|
||||
Agent.objects.select_related("site")
|
||||
.prefetch_related("agentchecks")
|
||||
.filter(site__client_id=request.data["clientPK"])
|
||||
)
|
||||
else:
|
||||
queryset = Agent.objects.select_related("site").prefetch_related(
|
||||
"agentchecks"
|
||||
)
|
||||
.order_by(order_by)
|
||||
)
|
||||
paginator = Paginator(queryset, pagination["rowsPerPage"])
|
||||
|
||||
queryset = queryset.only(
|
||||
"pk",
|
||||
"hostname",
|
||||
"agent_id",
|
||||
"site",
|
||||
"monitoring_type",
|
||||
"description",
|
||||
"needs_reboot",
|
||||
"overdue_text_alert",
|
||||
"overdue_email_alert",
|
||||
"overdue_time",
|
||||
"offline_time",
|
||||
"last_seen",
|
||||
"boot_time",
|
||||
"logged_in_username",
|
||||
"last_logged_in_user",
|
||||
"time_zone",
|
||||
"maintenance_mode",
|
||||
)
|
||||
ctx = {"default_tz": get_default_timezone()}
|
||||
serializer = AgentTableSerializer(
|
||||
paginator.get_page(pagination["page"]), many=True, context=ctx
|
||||
)
|
||||
|
||||
ret = {"agents": serializer.data, "total": paginator.count}
|
||||
return Response(ret)
|
||||
serializer = AgentTableSerializer(queryset, many=True, context=ctx)
|
||||
return Response(serializer.data)
|
||||
|
||||
|
||||
@api_view()
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
:table-class="{ 'table-bgcolor': !$q.dark.isActive, 'table-bgcolor-dark': $q.dark.isActive }"
|
||||
class="agents-tbl-sticky"
|
||||
:style="{ 'max-height': agentTableHeight }"
|
||||
:data="filter"
|
||||
:data="frame"
|
||||
:filter="search"
|
||||
:filter-method="filterTable"
|
||||
:columns="columns"
|
||||
|
@ -13,11 +13,9 @@
|
|||
row-key="id"
|
||||
binary-state-sort
|
||||
virtual-scroll
|
||||
:pagination.sync="agentPagination"
|
||||
:rows-per-page-options="[25, 50, 100, 200, 300, 500, 1000]"
|
||||
:pagination.sync="pagination"
|
||||
:rows-per-page-options="[0]"
|
||||
no-data-label="No Agents"
|
||||
rows-per-page-label="Agents per page:"
|
||||
@request="onRequest"
|
||||
>
|
||||
<!-- header slots -->
|
||||
<template v-slot:header-cell-smsalert="props">
|
||||
|
@ -346,6 +344,12 @@
|
|||
<q-tooltip>Pending Action Count: {{ props.row.pending_actions }}</q-tooltip>
|
||||
</q-icon>
|
||||
</q-td>
|
||||
<!-- needs reboot -->
|
||||
<q-td key="needsreboot">
|
||||
<q-icon v-if="props.row.needs_reboot" name="fas fa-power-off" color="primary">
|
||||
<q-tooltip>Reboot required</q-tooltip>
|
||||
</q-icon>
|
||||
</q-td>
|
||||
<q-td key="agentstatus">
|
||||
<q-icon v-if="props.row.status === 'overdue'" name="fas fa-signal" size="1.2em" color="negative">
|
||||
<q-tooltip>Agent overdue</q-tooltip>
|
||||
|
@ -357,12 +361,6 @@
|
|||
<q-tooltip>Agent online</q-tooltip>
|
||||
</q-icon>
|
||||
</q-td>
|
||||
<!-- needs reboot -->
|
||||
<q-td key="needsreboot">
|
||||
<q-icon v-if="props.row.needs_reboot" name="fas fa-power-off" color="primary">
|
||||
<q-tooltip>Reboot required</q-tooltip>
|
||||
</q-icon>
|
||||
</q-td>
|
||||
<q-td key="last_seen" :props="props">{{ formatDjangoDate(props.row.last_seen) }}</q-td>
|
||||
<q-td key="boot_time" :props="props">{{ bootTime(props.row.boot_time) }}</q-td>
|
||||
</q-tr>
|
||||
|
@ -415,7 +413,7 @@ import RunScript from "@/components/modals/agents/RunScript";
|
|||
|
||||
export default {
|
||||
name: "AgentTable",
|
||||
props: ["frame", "columns", "tab", "filter", "userName", "search", "visibleColumns", "agentTblPagination"],
|
||||
props: ["frame", "columns", "tab", "userName", "search", "visibleColumns"],
|
||||
components: {
|
||||
EditAgent,
|
||||
RebootLater,
|
||||
|
@ -427,6 +425,11 @@ export default {
|
|||
mixins: [mixins],
|
||||
data() {
|
||||
return {
|
||||
pagination: {
|
||||
rowsPerPage: 0,
|
||||
sortBy: "hostname",
|
||||
descending: false,
|
||||
},
|
||||
showSendCommand: false,
|
||||
showEditAgentModal: false,
|
||||
showRebootLaterModal: false,
|
||||
|
@ -438,15 +441,6 @@ export default {
|
|||
};
|
||||
},
|
||||
methods: {
|
||||
onRequest(props) {
|
||||
if (!!props.filter) return;
|
||||
const { page, rowsPerPage, sortBy, descending } = props.pagination;
|
||||
this.agentTblPagination.page = page;
|
||||
this.agentTblPagination.rowsPerPage = rowsPerPage;
|
||||
this.agentTblPagination.sortBy = sortBy;
|
||||
this.agentTblPagination.descending = descending;
|
||||
this.$emit("refreshEdit");
|
||||
},
|
||||
filterTable(rows, terms, cols, cellValue) {
|
||||
const lowerTerms = terms ? terms.toLowerCase() : "";
|
||||
let advancedFilter = false;
|
||||
|
@ -765,14 +759,6 @@ export default {
|
|||
agentTableLoading() {
|
||||
return this.$store.state.agentTableLoading;
|
||||
},
|
||||
agentPagination: {
|
||||
get: function () {
|
||||
return this.agentTblPagination;
|
||||
},
|
||||
set: function (newVal) {
|
||||
this.$emit("agentPagChanged", newVal);
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -46,11 +46,6 @@
|
|||
class="col-4"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section class="row">
|
||||
<div class="col-6">Agent table default records per page:</div>
|
||||
<div class="col-2"></div>
|
||||
<q-input v-model.number="agentsPerPage" type="number" filled style="max-width: 100px" />
|
||||
</q-card-section>
|
||||
</q-tab-panel>
|
||||
</q-tab-panels>
|
||||
|
||||
|
@ -73,7 +68,6 @@ export default {
|
|||
return {
|
||||
agentDblClickAction: "",
|
||||
defaultAgentTblTab: "",
|
||||
agentsPerPage: 50,
|
||||
tab: "ui",
|
||||
splitterModel: 20,
|
||||
agentDblClickOptions: [
|
||||
|
@ -111,7 +105,6 @@ export default {
|
|||
this.$axios.get("/core/dashinfo/").then(r => {
|
||||
this.agentDblClickAction = r.data.dbl_click_action;
|
||||
this.defaultAgentTblTab = r.data.default_agent_tbl_tab;
|
||||
this.agentsPerPage = r.data.agents_per_page;
|
||||
});
|
||||
},
|
||||
editUserPrefs() {
|
||||
|
@ -119,12 +112,10 @@ export default {
|
|||
userui: true,
|
||||
agent_dblclick_action: this.agentDblClickAction,
|
||||
default_agent_tbl_tab: this.defaultAgentTblTab,
|
||||
agents_per_page: this.agentsPerPage,
|
||||
};
|
||||
this.$axios.patch("/accounts/users/ui/", data).then(r => {
|
||||
this.notifySuccess("Preferences were saved!");
|
||||
this.$emit("edited");
|
||||
this.$emit("refresh");
|
||||
this.$emit("close");
|
||||
});
|
||||
},
|
||||
|
|
|
@ -195,7 +195,6 @@
|
|||
indicator-color="primary"
|
||||
align="left"
|
||||
narrow-indicator
|
||||
@input="tabChanged"
|
||||
>
|
||||
<q-tab name="server" icon="fas fa-server" label="Servers" />
|
||||
<q-tab name="workstation" icon="computer" label="Workstations" />
|
||||
|
@ -205,11 +204,10 @@
|
|||
<q-input
|
||||
v-model="search"
|
||||
style="width: 450px"
|
||||
label="Search (temporarily disabled)"
|
||||
label="Search"
|
||||
dense
|
||||
outlined
|
||||
clearable
|
||||
disable
|
||||
@clear="clearFilter"
|
||||
class="q-pr-md q-pb-xs"
|
||||
>
|
||||
|
@ -217,7 +215,7 @@
|
|||
<q-icon name="search" color="primary" />
|
||||
</template>
|
||||
<template v-slot:after>
|
||||
<q-btn disable round dense flat icon="filter_alt" :color="isFilteringTable ? 'green' : ''">
|
||||
<q-btn round dense flat icon="filter_alt" :color="isFilteringTable ? 'green' : ''">
|
||||
<q-menu>
|
||||
<q-list dense>
|
||||
<q-item-label header>Filter Agent Table</q-item-label>
|
||||
|
@ -320,16 +318,13 @@
|
|||
</q-input>
|
||||
</div>
|
||||
<AgentTable
|
||||
:frame="frame"
|
||||
:frame="filteredAgents"
|
||||
:columns="columns"
|
||||
:tab="tab"
|
||||
:filter="frozenAgents"
|
||||
:userName="user"
|
||||
:search="search"
|
||||
:visibleColumns="visibleColumns"
|
||||
:agentTblPagination="agentTblPagination"
|
||||
@refreshEdit="refreshEntireSite"
|
||||
@agentPagChanged="setAgentTblPagination"
|
||||
/>
|
||||
</template>
|
||||
<template v-slot:separator>
|
||||
|
@ -367,7 +362,7 @@
|
|||
</q-dialog>
|
||||
<!-- user preferences modal -->
|
||||
<q-dialog v-model="showUserPreferencesModal">
|
||||
<UserPreferences @close="showUserPreferencesModal = false" @edited="getDashInfo" @refresh="refreshEntireSite" />
|
||||
<UserPreferences @close="showUserPreferencesModal = false" @edited="getDashInfo" />
|
||||
</q-dialog>
|
||||
</q-layout>
|
||||
</template>
|
||||
|
@ -428,13 +423,6 @@ export default {
|
|||
filterRebootNeeded: false,
|
||||
currentTRMMVersion: null,
|
||||
showUserPreferencesModal: false,
|
||||
agentTblPagination: {
|
||||
rowsPerPage: 50,
|
||||
rowsNumber: null,
|
||||
sortBy: "hostname",
|
||||
descending: false,
|
||||
page: 1,
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
name: "smsalert",
|
||||
|
@ -452,8 +440,8 @@ export default {
|
|||
name: "checks-status",
|
||||
align: "left",
|
||||
field: "checks",
|
||||
sortable: false,
|
||||
//sort: (a, b, rowA, rowB) => parseInt(b.failing) - a.failing,
|
||||
sortable: true,
|
||||
sort: (a, b, rowA, rowB) => parseInt(b.failing) - a.failing,
|
||||
},
|
||||
{
|
||||
name: "client_name",
|
||||
|
@ -498,18 +486,12 @@ export default {
|
|||
name: "patchespending",
|
||||
field: "patches_pending",
|
||||
align: "left",
|
||||
sortable: false,
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "pendingactions",
|
||||
field: "pending_actions",
|
||||
align: "left",
|
||||
sortable: false,
|
||||
},
|
||||
{
|
||||
name: "agentstatus",
|
||||
field: "status",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
|
@ -518,13 +500,19 @@ export default {
|
|||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "agentstatus",
|
||||
field: "status",
|
||||
align: "left",
|
||||
sortable: false,
|
||||
},
|
||||
{
|
||||
name: "last_seen",
|
||||
label: "Last Response",
|
||||
field: "last_seen",
|
||||
sortable: true,
|
||||
align: "left",
|
||||
//sort: (a, b) => this.dateStringToUnix(a) - this.dateStringToUnix(b),
|
||||
sort: (a, b) => this.dateStringToUnix(a) - this.dateStringToUnix(b),
|
||||
},
|
||||
{
|
||||
name: "boot_time",
|
||||
|
@ -560,16 +548,6 @@ export default {
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
tabChanged(val) {
|
||||
if (this.allClientsActive) {
|
||||
this.loadAllClients();
|
||||
} else {
|
||||
this.loadFrame(this.selectedTree, false);
|
||||
}
|
||||
},
|
||||
setAgentTblPagination(val) {
|
||||
this.agentTblPagination = val;
|
||||
},
|
||||
toggleDark(val) {
|
||||
this.$q.dark.set(val);
|
||||
this.$axios.patch("/accounts/users/ui/", { dark_mode: val });
|
||||
|
@ -600,7 +578,7 @@ export default {
|
|||
|
||||
let execute = false;
|
||||
let urlType, id;
|
||||
let data = { pagination: this.agentTblPagination };
|
||||
let data = {};
|
||||
|
||||
if (typeof activenode === "string") {
|
||||
urlType = activenode.split("|")[0];
|
||||
|
@ -616,15 +594,10 @@ export default {
|
|||
|
||||
if (execute) {
|
||||
this.$store.commit("AGENT_TABLE_LOADING", true);
|
||||
// give time for vuex to set the tab, otherwise will always be 'server'
|
||||
setTimeout(() => {
|
||||
data.monType = this.tab;
|
||||
this.$axios.patch("/agents/listagents/", data).then(r => {
|
||||
this.frame = r.data.agents;
|
||||
this.agentTblPagination.rowsNumber = r.data.total;
|
||||
this.$store.commit("AGENT_TABLE_LOADING", false);
|
||||
});
|
||||
}, 500);
|
||||
this.$axios.patch("/agents/listagents/", data).then(r => {
|
||||
this.frame = r.data;
|
||||
this.$store.commit("AGENT_TABLE_LOADING", false);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -642,18 +615,10 @@ export default {
|
|||
},
|
||||
loadAllClients() {
|
||||
this.$store.commit("AGENT_TABLE_LOADING", true);
|
||||
// give time for vuex to set the tab, otherwise will always be 'server'
|
||||
setTimeout(() => {
|
||||
const data = {
|
||||
pagination: this.agentTblPagination,
|
||||
monType: this.tab,
|
||||
};
|
||||
this.$axios.patch("/agents/listagents/", data).then(r => {
|
||||
this.frame = r.data.agents;
|
||||
this.agentTblPagination.rowsNumber = r.data.total;
|
||||
this.$store.commit("AGENT_TABLE_LOADING", false);
|
||||
});
|
||||
}, 500);
|
||||
this.$axios.patch("/agents/listagents/").then(r => {
|
||||
this.frame = r.data;
|
||||
this.$store.commit("AGENT_TABLE_LOADING", false);
|
||||
});
|
||||
},
|
||||
showPolicyAdd(node) {
|
||||
if (node.children) {
|
||||
|
@ -747,10 +712,7 @@ export default {
|
|||
},
|
||||
getDashInfo(edited = true) {
|
||||
this.$store.dispatch("getDashInfo").then(r => {
|
||||
if (edited) {
|
||||
this.agentTblPagination.rowsPerPage = r.data.agents_per_page;
|
||||
this.$store.commit("SET_DEFAULT_AGENT_TBL_TAB", r.data.default_agent_tbl_tab);
|
||||
}
|
||||
if (edited) this.$store.commit("SET_DEFAULT_AGENT_TBL_TAB", r.data.default_agent_tbl_tab);
|
||||
this.darkMode = r.data.dark_mode;
|
||||
this.$q.dark.set(this.darkMode);
|
||||
this.currentTRMMVersion = r.data.trmm_version;
|
||||
|
@ -850,8 +812,9 @@ export default {
|
|||
allClientsActive() {
|
||||
return this.selectedTree === "";
|
||||
},
|
||||
frozenAgents() {
|
||||
return Object.freeze(this.frame);
|
||||
filteredAgents() {
|
||||
if (this.tab === "mixed") return Object.freeze(this.frame);
|
||||
return Object.freeze(this.frame.filter(k => k.monitoring_type === this.tab));
|
||||
},
|
||||
activeNode() {
|
||||
return {
|
||||
|
|
Loading…
Reference in New Issue