Policy Overview Add/Edit

This commit is contained in:
Josh Krawczyk
2020-04-16 10:56:52 -04:00
parent f8aaa2af46
commit fefb74815b
9 changed files with 999 additions and 45 deletions

View File

@@ -75,15 +75,18 @@
>
<q-td>{{ props.row.name }}</q-td>
<q-td>{{ props.row.desc }}</q-td>
<q-td>{{ props.row.applied_to }}</q-td>
<q-td>{{ props.row.actions }}</q-td>
<q-td>{{ props.row.active }}</q-td>
<q-td>{{ props.row.clients.length }}</q-td>
<q-td>{{ props.row.sites.length }}</q-td>
<q-td>{{ props.row.agents.length }}</q-td>
</q-tr>
</template>
</q-table>
</div>
<q-card-section></q-card-section>
<q-separator />
<q-card-section></q-card-section>
<q-card-section>
<PolicySubTableTabs />
</q-card-section>
</q-card>
</q-dialog>
<q-dialog v-model="showAddPolicyModal">
@@ -105,14 +108,14 @@ import { mapState } from "vuex";
import AddPolicy from "@/components/modals/automation/AddPolicy";
import EditPolicy from "@/components/modals/automation/EditPolicy";
import PolicyOverview from "@/components/modals/automation/PolicyOverview";
import PolicySubTableTabs from "@/components/PolicySubTableTabs"
export default {
name: "AutomationManager",
components: { AddPolicy, EditPolicy, PolicyOverview },
components: { AddPolicy, EditPolicy, PolicyOverview, PolicySubTableTabs },
mixins: [mixins],
data() {
return {
selectedRow: null,
showAddPolicyModal: false,
showEditPolicyModal: false,
showPolicyOverviewModal: false,
@@ -145,14 +148,28 @@ export default {
sortable: true
},
{
name: "applied_to",
label: "Applied To",
field: "applied_to",
name: "clients",
label: "Clients",
field: "clients",
align: "left",
sortable: false
},
{
name: "sites",
label: "Sites",
field: "sites",
align: "left",
sortable: false
},
{
name: "agents",
label: "Agents",
field: "agents",
align: "left",
sortable: false
}
],
visibleColumns: ["name", "desc", "active", "applied_to"]
visibleColumns: ["name", "desc", "active", "clients", "sites", "agents"]
};
},
methods: {
@@ -164,10 +181,12 @@ export default {
this.$store.commit("TOGGLE_AUTOMATION_MANAGER", false);
},
policyRowSelected(pk) {
this.selectedRow = pk;
this.$store.commit("setSelectedPolicy", pk);
this.$store.dispatch("loadPolicyChecks", pk);
},
clearRow() {
this.selectedRow = null;
this.$store.commit("setSelectedPolicy", null);
this.$store.commit("setPolicyChecks", {});
},
deletePolicy() {
this.$q
@@ -179,16 +198,17 @@ export default {
.onOk(() => {
axios.delete(`/automation/policies/${this.selectedRow}`).then(r => {
this.getPolicies();
this.notifySuccess(`Policy ${r.data} was deleted!`);
this.notifySuccess(`Policy was deleted!`);
});
});
}
},
},
computed: {
...mapState({
toggleAutomationManager: state => state.toggleAutomationManager,
policies: state => state.policies
})
policies: state => state.policies,
selectedRow: state => state.selectedPolicy
}),
},
mounted() {
this.getPolicies();

View File

@@ -0,0 +1,429 @@
<template>
<div v-if="Object.keys(checks).length === 0">No policy selected</div>
<div class="row" v-else>
<div class="col-12">
<q-btn size="sm" color="grey-5" icon="fas fa-plus" label="Add Check" text-color="black">
<q-menu>
<q-list dense style="min-width: 200px">
<q-item clickable v-close-popup @click="showAddDiskSpaceCheck = true">
<q-item-section side>
<q-icon size="xs" name="far fa-hdd" />
</q-item-section>
<q-item-section>Disk Space Check</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="showAddPingCheck = true">
<q-item-section side>
<q-icon size="xs" name="fas fa-network-wired" />
</q-item-section>
<q-item-section>Ping Check</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="showAddCpuLoadCheck = true">
<q-item-section side>
<q-icon size="xs" name="fas fa-microchip" />
</q-item-section>
<q-item-section>CPU Load Check</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="showAddMemCheck = true">
<q-item-section side>
<q-icon size="xs" name="fas fa-memory" />
</q-item-section>
<q-item-section>Memory Check</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="showAddWinSvcCheck = true">
<q-item-section side>
<q-icon size="xs" name="fas fa-cogs" />
</q-item-section>
<q-item-section>Windows Service Check</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="showAddScriptCheck = true">
<q-item-section side>
<q-icon size="xs" name="fas fa-terminal" />
</q-item-section>
<q-item-section>Script Check</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
<q-btn dense flat push @click="onRefresh(checks.id)" icon="refresh" />
<template v-if="allChecks === undefined || allChecks.length === 0">
<p>No Checks</p>
</template>
<template v-else>
<q-table
dense
class="checks-tbl-sticky"
:data="allChecks"
:columns="columns"
:row-key="row => row.id + row.check_type"
binary-state-sort
:pagination.sync="pagination"
hide-bottom
>
<!-- header slots -->
<template v-slot:header-cell-smsalert="props">
<q-th auto-width :props="props">
<q-icon name="phone_android" size="1.5em">
<q-tooltip>SMS Alert</q-tooltip>
</q-icon>
</q-th>
</template>
<template v-slot:header-cell-emailalert="props">
<q-th auto-width :props="props">
<q-icon name="email" size="1.5em">
<q-tooltip>Email Alert</q-tooltip>
</q-icon>
</q-th>
</template>
<template v-slot:header-cell-statusicon="props">
<q-th auto-width :props="props"></q-th>
</template>
<!-- body slots -->
<template slot="body" slot-scope="props" :props="props">
<q-tr @contextmenu="editCheckPK = props.row.id">
<!-- context menu -->
<q-menu context-menu>
<q-list dense style="min-width: 200px">
<q-item clickable v-close-popup @click="editCheck(props.row.check_type)">
<q-item-section side>
<q-icon name="edit" />
</q-item-section>
<q-item-section>Edit</q-item-section>
</q-item>
<q-item
clickable
v-close-popup
@click="deleteCheck(props.row.id, props.row.check_type)"
>
<q-item-section side>
<q-icon name="delete" />
</q-item-section>
<q-item-section>Delete</q-item-section>
</q-item>
<q-separator></q-separator>
<q-item clickable v-close-popup>
<q-item-section>Close</q-item-section>
</q-item>
</q-list>
</q-menu>
<!-- tds -->
<q-td>
<q-checkbox
dense
@input="checkAlertAction(props.row.id, props.row.check_type, 'text', props.row.text_alert)"
v-model="props.row.text_alert"
/>
</q-td>
<q-td>
<q-checkbox
dense
@input="checkAlertAction(props.row.id, props.row.check_type, 'email', props.row.email_alert)"
v-model="props.row.email_alert"
/>
</q-td>
<q-td v-if="props.row.status === 'pending'"></q-td>
<q-td v-else-if="props.row.status === 'passing'">
<q-icon style="font-size: 1.3rem;" color="positive" name="check_circle" />
</q-td>
<q-td v-else-if="props.row.status === 'failing'">
<q-icon style="font-size: 1.3rem;" color="negative" name="error" />
</q-td>
<q-td
v-if="props.row.check_type === 'diskspace'"
>Disk Space Drive {{ props.row.disk }} > {{props.row.threshold }}%</q-td>
<q-td
v-else-if="props.row.check_type === 'cpuload'"
>Avg CPU Load > {{ props.row.cpuload }}%</q-td>
<q-td
v-else-if="props.row.check_type === 'script'"
>Script check: {{ props.row.script.name }}</q-td>
<q-td
v-else-if="props.row.check_type === 'ping'"
>Ping {{ props.row.name }} ({{ props.row.ip }})</q-td>
<q-td
v-else-if="props.row.check_type === 'memory'"
>Avg memory usage > {{ props.row.threshold }}%</q-td>
<q-td
v-else-if="props.row.check_type === 'winsvc'"
>Service Check - {{ props.row.svc_display_name }}</q-td>
<q-td v-if="props.row.status === 'pending'">Awaiting First Synchronization</q-td>
<q-td v-else-if="props.row.status === 'passing'">
<q-badge color="positive">Passing</q-badge>
</q-td>
<q-td v-else-if="props.row.status === 'failing'">
<q-badge color="negative">Failing</q-badge>
</q-td>
<q-td v-if="props.row.check_type === 'ping'">
<span
style="cursor:pointer;color:blue;text-decoration:underline"
@click="moreInfo('Ping', props.row.more_info)"
>output</span>
</q-td>
<q-td v-else-if="props.row.check_type === 'script'">
<span
style="cursor:pointer;color:blue;text-decoration:underline"
@click="scriptMoreInfo(props.row)"
>output</span>
</q-td>
<q-td v-else>{{ props.row.more_info }}</q-td>
<q-td>{{ props.row.last_run }}</q-td>
</q-tr>
</template>
</q-table>
</template>
</div>
<!-- modals -->
<q-dialog v-model="showAddDiskSpaceCheck">
<AddDiskSpaceCheck @close="showAddDiskSpaceCheck = false" :policypk="checks.id" />
</q-dialog>
<q-dialog v-model="showEditDiskSpaceCheck">
<EditDiskSpaceCheck
@close="showEditDiskSpaceCheck = false"
:editCheckPK="editCheckPK"
:policypk="checks.id"
/>
</q-dialog>
<q-dialog v-model="showAddPingCheck">
<AddPingCheck @close="showAddPingCheck = false" :policypk="checks.id" />
</q-dialog>
<q-dialog v-model="showEditPingCheck">
<EditPingCheck
@close="showEditPingCheck = false"
:editCheckPK="editCheckPK"
:policypk="checks.id"
/>
</q-dialog>
<q-dialog v-model="showAddCpuLoadCheck">
<AddCpuLoadCheck @close="showAddCpuLoadCheck = false" :policypk="checks.id" />
</q-dialog>
<q-dialog v-model="showEditCpuLoadCheck">
<EditCpuLoadCheck
@close="showEditCpuLoadCheck = false"
:editCheckPK="editCheckPK"
:policypk="checks.id"
/>
</q-dialog>
<q-dialog v-model="showAddMemCheck">
<AddMemCheck @close="showAddMemCheck = false" :policypk="checks.id" />
</q-dialog>
<q-dialog v-model="showEditMemCheck">
<EditMemCheck
@close="showEditMemCheck = false"
:editCheckPK="editCheckPK"
:policypk="checks.id"
/>
</q-dialog>
<q-dialog v-model="showAddWinSvcCheck">
<AddWinSvcCheck @close="showAddWinSvcCheck = false" :policypk="checks.id" />
</q-dialog>
<q-dialog v-model="showEditWinSvcCheck">
<EditWinSvcCheck
@close="showEditWinSvcCheck = false"
:editCheckPK="editCheckPK"
:policypk="checks.id"
/>
</q-dialog>
<!-- script check -->
<q-dialog v-model="showAddScriptCheck">
<AddScriptCheck @close="showAddScriptCheck = false" :policypk="checks.id" />
</q-dialog>
<q-dialog v-model="showEditScriptCheck">
<EditScriptCheck
@close="showEditScriptCheck = false"
:editCheckPK="editCheckPK"
:policypk="checks.id"
/>
</q-dialog>
</div>
</template>
<script>
import axios from "axios";
import { mapState } from "vuex";
import mixins from "@/mixins/mixins";
import AddDiskSpaceCheck from "@/components/modals/checks/AddDiskSpaceCheck";
import EditDiskSpaceCheck from "@/components/modals/checks/EditDiskSpaceCheck";
import AddPingCheck from "@/components/modals/checks/AddPingCheck";
import EditPingCheck from "@/components/modals/checks/EditPingCheck";
import AddCpuLoadCheck from "@/components/modals/checks/AddCpuLoadCheck";
import EditCpuLoadCheck from "@/components/modals/checks/EditCpuLoadCheck";
import AddMemCheck from "@/components/modals/checks/AddMemCheck";
import EditMemCheck from "@/components/modals/checks/EditMemCheck";
import AddWinSvcCheck from "@/components/modals/checks/AddWinSvcCheck";
import EditWinSvcCheck from "@/components/modals/checks/EditWinSvcCheck";
import AddScriptCheck from "@/components/modals/checks/AddScriptCheck";
import EditScriptCheck from "@/components/modals/checks/EditScriptCheck";
export default {
name: "PolicyChecksTab",
components: {
AddDiskSpaceCheck,
EditDiskSpaceCheck,
AddPingCheck,
EditPingCheck,
AddCpuLoadCheck,
EditCpuLoadCheck,
AddMemCheck,
EditMemCheck,
AddWinSvcCheck,
EditWinSvcCheck,
AddScriptCheck,
EditScriptCheck
},
mixins: [mixins],
data() {
return {
showAddDiskSpaceCheck: false,
showEditDiskSpaceCheck: false,
showAddPingCheck: false,
showEditPingCheck: false,
showAddCpuLoadCheck: false,
showEditCpuLoadCheck: false,
showAddMemCheck: false,
showEditMemCheck: false,
showAddWinSvcCheck: false,
showEditWinSvcCheck: false,
showAddScriptCheck: false,
showEditScriptCheck: false,
editCheckPK: null,
scriptInfo: {},
columns: [
{ name: "smsalert", field: "text_alert", align: "left" },
{ name: "emailalert", field: "email_alert", align: "left" },
{ name: "statusicon", align: "left" },
{ name: "desc", label: "Description", align: "left" },
{ name: "status", label: "Status", field: "status", align: "left" },
{
name: "moreinfo",
label: "More Info",
field: "more_info",
align: "left"
},
{
name: "datetime",
label: "Date / Time",
field: "last_run",
align: "left"
}
],
pagination: {
rowsPerPage: 9999
}
};
},
methods: {
checkAlertAction(pk, category, alert_type, alert_action) {
const action = alert_action ? "enabled" : "disabled";
const data = {
alertType: alert_type,
checkid: pk,
category: category,
action: action
};
const alertColor = alert_action ? "positive" : "warning";
axios.patch("/checks/checkalert/", data).then(r => {
this.$q.notify({
color: alertColor,
icon: "fas fa-check-circle",
message: `${alert_type} alerts ${action}`
});
});
},
onRefresh(id) {
this.$store.dispatch("loadPolicyChecks", id);
},
moreInfo(name, output) {
this.$q.dialog({
title: `${name} output`,
style: "width: 35vw; max-width: 50vw",
message: `<pre>${output}</pre>`,
html: true,
dark: true
});
},
scriptMoreInfo(props) {
this.scriptInfo = props;
this.showScriptOutput = true;
},
editCheck(category) {
switch (category) {
case "diskspace":
this.showEditDiskSpaceCheck = true;
break;
case "ping":
this.showEditPingCheck = true;
break;
case "cpuload":
this.showEditCpuLoadCheck = true;
break;
case "memory":
this.showEditMemCheck = true;
break;
case "winsvc":
this.showEditWinSvcCheck = true;
break;
case "script":
this.showEditScriptCheck = true;
break;
default:
return false;
}
},
deleteCheck(pk, check_type) {
this.$q
.dialog({
title: "Are you sure?",
message: `Delete ${check_type} check`,
cancel: true,
persistent: true
})
.onOk(() => {
const data = { pk: pk, checktype: check_type };
axios
.delete("checks/deletestandardcheck/", { data: data })
.then(r => {
this.$store.dispatch("loadPolicyChecks", this.checks.pk);
this.notifySuccess("Check was deleted!");
})
.catch(e => this.notifyError(e.response.data.error));
});
}
},
computed: {
...mapState({
checks: state => state.policyChecks
}),
allChecks() {
return [
...this.checks.diskchecks,
...this.checks.cpuloadchecks,
...this.checks.memchecks,
...this.checks.scriptchecks,
...this.checks.winservicechecks,
...this.checks.pingchecks
];
}
}
};
</script>
<style lang="stylus">
.checks-tbl-sticky {
.q-table__middle {
max-height: 25vh;
}
.q-table__top, .q-table__bottom, thead tr:first-child th {
background-color: #f5f4f2;
}
thead tr:first-child th {
position: sticky;
top: 0;
opacity: 1;
z-index: 1;
}
}
</style>

View File

@@ -0,0 +1,40 @@
<template>
<div class="q-pa-md">
<q-tabs
v-model="subtab"
dense
inline-label
class="text-grey"
active-color="primary"
indicator-color="primary"
align="left"
narrow-indicator
no-caps
>
<q-tab name="checks" icon="fas fa-check-double" label="Checks" />
</q-tabs>
<q-separator />
<q-tab-panels v-model="subtab" :animated="false">
<q-tab-panel name="checks">
<PolicyChecksTab />
</q-tab-panel>
</q-tab-panels>
</div>
</template>
<script>
import PolicyChecksTab from '@/components/PolicyChecksTab';
export default {
name: "PolicySubTableTabs",
components: {
PolicyChecksTab,
},
data() {
return {
subtab: 'checks'
}
}
};
</script>

View File

@@ -1,5 +1,5 @@
<template>
<q-card style="width: 40vw">
<q-card style="width: 60vw">
<q-form @submit.prevent="addPolicy">
<q-card-section class="row items-center">
<div class="text-h6">Add Policy</div>
@@ -15,7 +15,73 @@
<q-card-section class="row">
<div class="col-2">Description:</div>
<div class="col-10">
<q-input outlined dense v-model="desc" type="textarea" />
<q-input outlined dense v-model="desc" />
</div>
</q-card-section>
<q-card-section class="row">
<div class="col-2">Active:</div>
<div class="col-10">
<q-toggle v-model="active" color="green" />
</div>
</q-card-section>
<q-card-section class="row">
<div class="col-2">Clients:</div>
<div class="col-10">
<q-select
v-model="selectedClients"
:options="clientOptions"
filled
multiple
use-chips
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey">
No Results
</q-item-section>
</q-item>
</template>
</q-select>
</div>
</q-card-section>
<q-card-section class="row">
<div class="col-2">Sites:</div>
<div class="col-10">
<q-select
v-model="selectedSites"
:options="siteOptions"
filled
multiple
use-chips
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey">
No Results
</q-item-section>
</q-item>
</template>
</q-select>
</div>
</q-card-section>
<q-card-section class="row">
<div class="col-2">Agents:</div>
<div class="col-10">
<q-select
v-model="selectedAgents"
:options="agentOptions"
filled
multiple
use-chips
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey">
No Results
</q-item-section>
</q-item>
</template>
</q-select>
</div>
</q-card-section>
<q-card-section class="row items-center">
@@ -34,7 +100,14 @@ export default {
data() {
return {
name: "",
desc: ""
desc: "",
active: false,
selectedAgents: [],
selectedSites: [],
selectedClients: [],
clientOptions: [],
siteOptions: [],
agentOptions: [],
};
},
methods: {
@@ -45,22 +118,78 @@ export default {
}
this.$q.loading.show();
let formData = new FormData();
formData.append("name", this.name);
formData.append("desc", this.desc);
axios
.post("/automation/policies/", formData)
let formData = {
name: this.name,
desc: this.desc,
active: this.active,
agents: this.selectedAgents.map(agent => agent.value),
sites: this.selectedSites.map(site => site.value),
clients: this.selectedClients.map(client => client.value)
};
axios.post("/automation/policies/", formData)
.then(r => {
this.$q.loading.hide();
this.$emit("close");
this.$emit("added");
this.notifySuccess("Policy added! Edit the policy to add Checks!");
this.notifySuccess("Policy added! Now you can add Tasks and Checks!");
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data);
});
}
},
getClients() {
axios.get(`/clients/listclients/`).then(r => {
this.clientOptions = r.data.map(client => {
return {
label: client.client,
value: client.id
}
});
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data);
});
},
getSites() {
axios.get(`/clients/listsites/`).then(r => {
this.siteOptions = r.data.map(site => {
return {
label: `${site.client_name}\\${site.site}`,
value: site.id
}
});
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data);
});
},
getAgents() {
axios.get(`/agents/listagents/`).then(r => {
this.agentOptions = r.data.map(agent => {
return {
label: `${agent.client}\\${agent.site}\\${agent.hostname}`,
value: agent.pk
}
});
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data);
});
},
},
created() {
this.getClients();
this.getSites();
this.getAgents();
}
};
</script>

View File

@@ -1,5 +1,5 @@
<template>
<q-card style="width: 40vw">
<q-card style="width: 60vw">
<q-form @submit.prevent="editPolicy">
<q-card-section class="row items-center">
<div class="text-h6">Edit Policy</div>
@@ -15,7 +15,73 @@
<q-card-section class="row">
<div class="col-2">Description:</div>
<div class="col-10">
<q-input outlined dense v-model="desc" type="textarea" />
<q-input outlined dense v-model="desc" />
</div>
</q-card-section>
<q-card-section class="row">
<div class="col-2">Active:</div>
<div class="col-10">
<q-toggle v-model="active" color="green" />
</div>
</q-card-section>
<q-card-section class="row">
<div class="col-2">Clients:</div>
<div class="col-10">
<q-select
v-model="selectedClients"
:options="clientOptions"
filled
multiple
use-chips
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey">
No Results
</q-item-section>
</q-item>
</template>
</q-select>
</div>
</q-card-section>
<q-card-section class="row">
<div class="col-2">Sites:</div>
<div class="col-10">
<q-select
v-model="selectedSites"
:options="siteOptions"
filled
multiple
use-chips
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey">
No Results
</q-item-section>
</q-item>
</template>
</q-select>
</div>
</q-card-section>
<q-card-section class="row">
<div class="col-2">Agents:</div>
<div class="col-10">
<q-select
v-model="selectedAgents"
:options="agentOptions"
filled
multiple
use-chips
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey">
No Results
</q-item-section>
</q-item>
</template>
</q-select>
</div>
</q-card-section>
<q-card-section class="row items-center">
@@ -37,15 +103,41 @@ export default {
return {
name: "",
desc: "",
associations: []
active: false,
selectedAgents: [],
selectedSites: [],
selectedClients: [],
clientOptions: [],
siteOptions: [],
agentOptions: [],
};
},
methods: {
getPolicy() {
axios.get(`/automation/policies/${this.pk}/`).then(r => {
this.name = r.data.name;
this.desc = r.data.desc;
})
this.active = r.data.active;
this.selectedAgents = r.data.agents.map(agent => {
return {
label: agent.hostname,
value: agent.pk
}
});
this.selectedSites = r.data.sites.map(site => {
return {
label: site.site,
value: site.id
}
});
this.selectedClients = r.data.clients.map(client => {
return {
label: client.client,
value: client.id
}
});
});
},
editPolicy() {
if (!this.name) {
@@ -54,10 +146,15 @@ export default {
}
this.$q.loading.show();
let formData = new FormData();
formData.append("name", this.name);
formData.append("desc", this.desc);
let formData = {
name: this.name,
desc: this.desc,
active: this.active,
agents: this.selectedAgents.map(agent => agent.value),
sites: this.selectedSites.map(site => site.value),
clients: this.selectedClients.map(client => client.value)
}
axios.put(`/automation/policies/${this.pk}/`, formData)
.then(r => {
@@ -70,10 +167,58 @@ export default {
this.$q.loading.hide();
this.notifyError(e.response.data);
});
}
},
getClients() {
axios.get(`/clients/listclients/`).then(r => {
this.clientOptions = r.data.map(client => {
return {
label: client.client,
value: client.id
}
});
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data);
});
},
getSites() {
axios.get(`/clients/listsites/`).then(r => {
this.siteOptions = r.data.map(site => {
return {
label: `${site.client_name}\\${site.site}`,
value: site.id
}
});
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data);
});
},
getAgents() {
axios.get(`/agents/listagents/`).then(r => {
this.agentOptions = r.data.map(agent => {
return {
label: `${agent.client}\\${agent.site}\\${agent.hostname}`,
value: agent.pk
}
});
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data);
});
},
},
created() {
this.getPolicy();
this.getClients();
this.getSites();
this.getAgents();
}
};
</script>

View File

@@ -1,7 +1,166 @@
<template>
<div>Policy Overview</div>
<q-card style="width: 600px; max-width: 60vw">
<q-bar>
<q-btn @click="getPolicyTree" class="q-mr-sm" dense flat push icon="refresh" />Policy Overview
<q-space />
<q-btn dense flat icon="close" v-close-popup>
<q-tooltip content-class="bg-white text-primary">Close</q-tooltip>
</q-btn>
</q-bar>
<q-splitter
v-model="splitterModel"
style="height: 400px"
>
<template v-slot:before>
<div class="q-pa-md">
<q-tree
ref="Tree"
:nodes="clientSiteTree"
node-key="label"
:selected.sync="selected"
selected-color="primary"
@update:selected="loadPolicyDetails"
default-expand-all
>
</q-tree>
</div>
</template>
<template v-slot:after>
<q-tab-panels
v-model="selectedTab"
animated
transition-prev="jump-up"
transition-next="jump-up"
>
<q-tab-panel name="Checks">
<p>List Checks</p>
</q-tab-panel>
<q-tab-panel name="Tasks">
<p>List Tasks</p>
</q-tab-panel>
</q-tab-panels>
</template>
</q-splitter>
</q-card>
</template>
<script>
import axios from "axios";
import mixins from "@/mixins/mixins";
export default {
name: "PolicyOverview",
mixins: [mixins],
data () {
return {
splitterModel: 50,
selected: "",
selectedPolicy: {},
selectedTab: "Checks",
clientSiteTree: [],
}
},
created() {
this.getPolicyTree();
},
methods: {
getPolicyTree() {
axios.get(`/automation/policies/overview/`).then(r => {
this.processTreeDataFromApi(r.data);
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data);
});
},
loadPolicyDetails(key) {
if (key === undefined) {return}
let node = this.$refs.Tree.getNodeByKey(key);
axios.get(`/automation/policies/${node.id}/`).then(r => {
this.selectedPolicy = r.data
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data);
});
},
processTreeDataFromApi(data) {
/* Structure
* [{
* "client_name_1": {
* "policies": [
* {
* id: 1
* name: "Policy Name 1"
* }
* ]
* "site_name_1": {
* "policies": []
* }
* }
* }]
*/
var result = [];
for (let client in data) {
var client_temp = {};
client_temp["label"] = client;
client_temp["icon"] = "business";
client_temp["selectable"] = false;
client_temp["children"] = [];
// Add any policies assigned to client
if (data[client].policies.length > 0) {
for (let policy in data[client].policies)
client_temp["children"].push({
label: data[client].policies[policy].name,
icon: 'policy',
id: data[client].policies[policy].id
});
}
// Iterate through Sites
for (let site in data[client].sites) {
var site_temp = {}
site_temp["label"] = site;
site_temp["icon"] = "apartment";
site_temp["selectable"] = false;
// Add any policies assigned to site
if (data[client].sites[site].policies.length > 0) {
site_temp["children"] = [];
for (let policy in data[client].sites[site].policies) {
site_temp["children"].push({
label: data[client].sites[site].policies[policy].name,
icon: 'policy',
id: data[client].sites[site].policies[policy].id
});
}
}
// Add Site to Client children array
client_temp.children.push(site_temp);
}
// Add Client and it's Sites to result array
result.push(client_temp);
}
this.clientSiteTree = result;
}
}
};
</script>

View File

@@ -42,7 +42,7 @@ import { mapState } from "vuex";
import mixins from "@/mixins/mixins";
export default {
name: "AddCpuLoadCheck",
props: ["agentpk"],
props: ["agentpk", "policypk"],
mixins: [mixins],
data() {
return {
@@ -53,8 +53,10 @@ export default {
},
methods: {
addCheck() {
pk = (this.policypk) ? {policy: policypk} : {pk: agentpk}
const data = {
pk: this.agentpk,
pk,
check_type: "cpuload",
threshold: this.threshold,
failure: this.failure
@@ -63,7 +65,13 @@ export default {
.post("/checks/addstandardcheck/", data)
.then(r => {
this.$emit("close");
this.$store.dispatch("loadChecks", this.agentpk);
if (this.policypk) {
this.$store.dispatch("loadPolicyChecks", this.policypk);
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
this.notifySuccess("CPU load check was added!");
})
.catch(e => this.notifyError(e.response.data.error));

View File

@@ -45,7 +45,7 @@ import { mapState } from "vuex";
import mixins from "@/mixins/mixins";
export default {
name: "AddPingCheck",
props: ["agentpk"],
props: ["agentpk", "policypk"],
mixins: [mixins],
data() {
return {
@@ -57,21 +57,32 @@ export default {
},
methods: {
addCheck() {
let pk = (this.policypk) ? {policy: this.policypk} : {pk: this.agentpk}
const data = {
pk: this.agentpk,
...pk,
check_type: "ping",
failures: this.failure,
name: this.pingname,
ip: this.pingip,
};
axios
.post("/checks/addstandardcheck/", data)
axios.post("/checks/addstandardcheck/", data)
.then(r => {
this.$emit("close");
this.$store.dispatch("loadChecks", this.agentpk);
if (this.policypk) {
this.$store.dispatch("loadPolicyChecks", this.policypk);
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
this.notifySuccess("Ping check was added!");
})
.catch(e => this.notifyError(e.response.data.error));
.catch(e => {
this.notifyError(e.response.data);
console.log(e.response.data)
});
}
}
};

View File

@@ -24,6 +24,8 @@ export const store = new Vuex.Store({
winUpdates: {},
agentChecks: {},
automatedTasks: {},
selectedPolicy: null,
policyChecks: {},
agentTableLoading: false,
treeLoading: false,
installedSoftware: [],
@@ -108,6 +110,9 @@ export const store = new Vuex.Store({
SET_AUTOMATED_TASKS(state, tasks) {
state.automatedTasks = tasks;
},
setPolicyChecks(state, checks) {
state.policyChecks = checks;
},
destroySubTable(state) {
(state.agentSummary = {}),
(state.agentChecks = {}),
@@ -120,7 +125,10 @@ export const store = new Vuex.Store({
},
SET_POLICIES(state, policies) {
state.policies = policies;
}
},
setSelectedPolicy(state, pk) {
state.selectedPolicy = pk;
},
},
actions: {
getPolicies(context) {
@@ -158,6 +166,11 @@ export const store = new Vuex.Store({
context.commit("setChecks", r.data);
});
},
loadPolicyChecks(context, pk) {
axios.get(`/checks/${pk}/loadpolicychecks/`).then(r => {
context.commit("setPolicyChecks", r.data);
});
},
getUpdatedSites(context) {
axios.get("/clients/loadclients/").then(r => {
context.commit("getUpdatedSites", r.data);