Merge pull request #14 from sadnub/feature-policies-alerts

Automation UI improvements and Relations View
This commit is contained in:
wh1te909
2020-05-18 18:11:13 -07:00
committed by GitHub
7 changed files with 222 additions and 99 deletions

View File

@@ -19,7 +19,7 @@
unelevated
no-caps
icon="add"
@click="showPolicyFormModal = true;"
@click="showAddPolicyModal"
/>
<q-btn
ref="edit"
@@ -82,9 +82,18 @@
<q-td>{{ props.row.name }}</q-td>
<q-td>{{ props.row.desc }}</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-td>
<q-btn
:label="`See Related (${props.row.clients.length + props.row.sites.length + props.row.agents.length}+)`"
color="primary"
dense
flat
unelevated
no-caps
@click="showRelationsModal(props.row)"
size="sm"
/>
</q-td>
</q-tr>
</template>
</q-table>
@@ -100,6 +109,9 @@
<q-dialog v-model="showPolicyOverviewModal">
<PolicyOverview @close="showPolicyOverviewModal = false" />
</q-dialog>
<q-dialog v-model="showRelationsViewModal">
<RelationsView :policy="policy" @close="closeRelationsModal" />
</q-dialog>
</div>
</template>
@@ -109,15 +121,18 @@ import { mapState } from "vuex";
import PolicyForm from "@/components/automation/modals/PolicyForm";
import PolicyOverview from "@/components/automation/PolicyOverview";
import PolicySubTableTabs from "@/components/automation/PolicySubTableTabs";
import RelationsView from "@/components/automation/modals/RelationsView";
export default {
name: "AutomationManager",
components: { PolicyForm, PolicyOverview, PolicySubTableTabs },
components: { PolicyForm, PolicyOverview, PolicySubTableTabs, RelationsView },
mixins: [mixins],
data() {
return {
showPolicyFormModal: false,
showPolicyOverviewModal: false,
showRelationsViewModal: false,
policy: null,
selected: [],
pagination: {
rowsPerPage: 0,
@@ -148,28 +163,14 @@ export default {
sortable: true
},
{
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",
name: "actions",
label: "Actions",
field: "actions",
align: "left",
sortable: false
}
],
visibleColumns: ["name", "desc", "active", "clients", "sites", "agents"]
visibleColumns: ["name", "desc", "active", "actions"]
};
},
methods: {
@@ -205,6 +206,18 @@ export default {
this.notifyError(`An Error occured while deleting policy`);
});
});
},
showRelationsModal(policy) {
this.policy = policy;
this.showRelationsViewModal = true;
},
closeRelationsModal() {
this.policy = null;
this.showRelationsViewModal = false;
},
showAddPolicyModal() {
this.clearRow();
this.showPolicyFormModal = true;
}
},
computed: {

View File

@@ -1,5 +1,5 @@
<template>
<div v-if="Object.keys(checks).length === 0">No policy selected</div>
<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">

View File

@@ -13,7 +13,7 @@
<q-tree
ref="Tree"
:nodes="clientSiteTree"
node-key="label"
node-key="id"
:selected.sync="selected"
selected-color="primary"
@update:selected="loadPolicyDetails"
@@ -123,14 +123,20 @@ export default {
var result = [];
// Used by tree for unique identification
let unique_id = 0;
for (let client in data) {
var client_temp = {};
client_temp["label"] = client;
client_temp["id"] = unique_id;
client_temp["icon"] = "business";
client_temp["selectable"] = false;
client_temp["children"] = [];
unique_id--;
// Add any policies assigned to client
if (data[client].policies.length > 0) {
for (let policy in data[client].policies)
@@ -145,9 +151,12 @@ export default {
for (let site in data[client].sites) {
var site_temp = {};
site_temp["label"] = site;
site_temp["id"] = unique_id;
site_temp["icon"] = "apartment";
site_temp["selectable"] = false;
unique_id--;
// Add any policies assigned to site
if (data[client].sites[site].policies.length > 0) {
site_temp["children"] = [];

View File

@@ -27,34 +27,64 @@
<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>
<q-select
v-model="selectedClients"
:options="clientOptions"
filled
multiple
use-chips
options-selected-class="text-green"
>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey">No Results</q-item-section>
</q-item>
</template>
<template v-slot:option="props">
<q-item
v-bind="props.itemProps"
v-on="props.itemEvents"
>
<q-item-section avatar>
<q-icon v-if="props.selected" name="check" />
</q-item-section>
<q-item-section>
<q-item-label v-html="props.opt.label" />
</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>
<q-select
v-model="selectedSites"
:options="siteOptions"
filled
multiple
use-chips
options-selected-class="text-green"
>
<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>
<template v-slot:option="props">
<q-item
v-bind="props.itemProps"
v-on="props.itemEvents"
>
<q-item-section avatar>
<q-icon v-if="props.selected" name="check" />
</q-item-section>
<q-item-section>
<!-- <q-item-label overline>{{ props.opt.client }}</q-item-label> -->
<q-item-label v-html="props.opt.label" />
<q-item-label caption>{{ props.opt.client }}</q-item-label>
</q-item-section>
</q-item>
</template>
</q-select>
@@ -80,12 +110,10 @@ export default {
name: "",
desc: "",
active: false,
selectedAgents: [],
selectedSites: [],
selectedClients: [],
clientOptions: [],
siteOptions: [],
agentOptions: []
siteOptions: []
};
},
computed: {
@@ -95,23 +123,26 @@ export default {
},
methods: {
getPolicy() {
this.$store.dispatch("automation/loadPolicy", 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 => ({
label: agent.hostname,
value: agent.pk
}) );
this.selectedSites = r.data.sites.map(site => ({
label: site.site,
value: site.id
}) );
this.selectedClients = r.data.clients.map(client => ({
label: client.client,
value: client.id
}) );
});
this.$q.loading.show();
this.$store
.dispatch("automation/loadPolicy", this.pk)
.then(r => {
this.$q.loading.hide();
this.name = r.data.name;
this.desc = r.data.desc;
this.active = r.data.active;
this.selectedSites = r.data.sites.map(site => ({
label: site.site,
value: site.id
}) );
this.selectedClients = r.data.clients.map(client => ({
label: client.client,
value: client.id
}) );
});
},
submit() {
if (!this.name) {
@@ -126,7 +157,6 @@ export default {
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)
};
@@ -164,10 +194,6 @@ export default {
.dispatch("loadClients")
.then(r => {
this.clientOptions = this.formatClients(r.data);
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data);
});
},
getSites() {
@@ -175,21 +201,6 @@ export default {
.dispatch("loadSites")
.then(r => {
this.siteOptions = this.formatSites(r.data);
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data);
});
},
getAgents() {
this.$store
.dispatch("loadAgents")
.then(r => {
this.agentOptions = this.formatAgents(r.data);
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data);
});
}
},
@@ -201,7 +212,6 @@ export default {
this.getClients();
this.getSites();
this.getAgents();
}
};
</script>

View File

@@ -0,0 +1,97 @@
<template>
<q-card style="width: 60vw">
<q-card-section class="row items-center">
<div class="text-h6">{{ policy.name }} Relations</div>
<q-space />
<q-btn icon="close" flat round dense v-close-popup />
</q-card-section>
<q-card-section>
<q-tabs
v-model="tab"
dense
inline-label
class="text-grey"
active-color="primary"
indicator-color="primary"
align="left"
narrow-indicator
no-caps
>
<q-tab name="clients" label="Clients" />
<q-tab name="sites" label="Sites" />
<q-tab name="agents" label="Agents" />
</q-tabs>
<q-separator />
<q-tab-panels v-model="tab" :animated="false">
<q-tab-panel name="clients">
<div class="text-h6">Clients</div>
<q-list separator padding >
<q-item :key="item.id" v-for="item in related.clients">
<q-item-section>
<q-item-label>{{ item.client }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-tab-panel>
<q-tab-panel name="sites">
<div class="text-h6">Sites</div>
<q-list separator padding >
<q-item :key="item.id" v-for="item in related.sites">
<q-item-section>
<q-item-label>{{ item.site }}</q-item-label>
<q-item-label caption>{{ item.client_name }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-tab-panel>
<q-tab-panel name="agents">
<div class="text-h6">Agents</div>
<q-list separator padding>
<q-item :key="item.pk" v-for="item in related.agents">
<q-item-section>
<q-item-label>{{ item.hostname }}</q-item-label>
<q-item-label caption>{{ item.client }} {{ item.site }}</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-tab-panel>
</q-tab-panels>
</q-card-section>
</q-card>
</template>
<script>
export default {
name: "RelationsView",
props: {
policy: {
type: Object,
required: true
}
},
data() {
return {
tab: 'clients',
related: {}
}
},
mounted() {
this.$q.loading.show();
this.$store
.dispatch("automation/getRelated", this.policy.id)
.then(r => {
this.$q.loading.hide();
this.related = r.data
})
.catch(e => {
this.$q.loading.hide();
});
}
}
</script>

View File

@@ -1,28 +1,19 @@
export default {
methods: {
formatClients(clients) {
return clients.map(client => {
return {
return clients.map(client => ({
label: client.client,
value: client.id
};
});
})
);
},
formatSites(sites) {
return sites.map(site => {
return {
label: `${site.client_name}\\${site.site}`,
value: site.id
};
});
},
formatAgents(agents) {
return agents.map(agent => {
return {
label: `${agent.client}\\${agent.site}\\${agent.hostname}`,
value: agent.pk
};
});
},
return sites.map(site => ({
label: site.site,
value: site.id,
client: site.client_name
})
);
}
}
};

View File

@@ -56,12 +56,15 @@ export default {
return axios.post("/automation/policies/", data);
},
editPolicy(context, data) {
return axios.put(`/automation/policies/${data.id}/`, data)
return axios.put(`/automation/policies/${data.id}/`, data);
},
deletePolicy(context, pk) {
return axios.delete(`/automation/policies/${pk}`).then(r => {
return axios.delete(`/automation/policies/${pk}/`).then(r => {
context.dispatch("loadPolicies");
});
},
getRelated(context, pk) {
return axios.get(`/automation/policies/${pk}/related/`);
}
}
}