mirror of
https://github.com/jpros/tacticalrmm-web.git
synced 2026-03-01 07:41:00 +00:00
Merge pull request #337 from sadnub/develop
clients and sites rework and custom fields
This commit is contained in:
@@ -133,7 +133,6 @@ export default {
|
||||
})
|
||||
.catch(e => {
|
||||
this.$q.loading.hide();
|
||||
console.log({ e });
|
||||
this.notifyError("There was an issue resolving alert");
|
||||
});
|
||||
},
|
||||
|
||||
187
src/components/ClientsManager.vue
Normal file
187
src/components/ClientsManager.vue
Normal file
@@ -0,0 +1,187 @@
|
||||
<template>
|
||||
<q-dialog ref="dialog" @hide="onHide">
|
||||
<div class="q-dialog-plugin" style="width: 90vw; max-width: 90vw">
|
||||
<q-card>
|
||||
<q-bar>
|
||||
<q-btn @click="getClients" class="q-mr-sm" dense flat push icon="refresh" />Clients Manager
|
||||
<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>
|
||||
<div class="q-pa-sm" style="min-height: 65vh; max-height: 65vh">
|
||||
<div class="q-gutter-sm">
|
||||
<q-btn label="New" dense flat push unelevated no-caps icon="add" @click="showAddClient" />
|
||||
</div>
|
||||
<q-table
|
||||
dense
|
||||
:data="clients"
|
||||
:columns="columns"
|
||||
:pagination.sync="pagination"
|
||||
row-key="id"
|
||||
binary-state-sort
|
||||
hide-pagination
|
||||
virtual-scroll
|
||||
:rows-per-page-options="[0]"
|
||||
no-data-label="No Clients"
|
||||
>
|
||||
<!-- body slots -->
|
||||
<template v-slot:body="props">
|
||||
<q-tr :props="props" class="cursor-pointer" @dblclick="showEditClient(props.row)">
|
||||
<!-- context menu -->
|
||||
<q-menu context-menu>
|
||||
<q-list dense style="min-width: 200px">
|
||||
<q-item clickable v-close-popup @click="showEditClient(props.row)">
|
||||
<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="showClientDeleteModal(props.row)">
|
||||
<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 @click="showAddSite(props.row)">
|
||||
<q-item-section side>
|
||||
<q-icon name="add" />
|
||||
</q-item-section>
|
||||
<q-item-section>Add Site</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>
|
||||
<!-- name -->
|
||||
<q-td>
|
||||
{{ props.row.name }}
|
||||
</q-td>
|
||||
<q-td>
|
||||
<span
|
||||
style="cursor: pointer; text-decoration: underline"
|
||||
class="text-primary"
|
||||
@click="showSitesTable(props.row)"
|
||||
>Show Sites</span
|
||||
>
|
||||
</q-td>
|
||||
</q-tr>
|
||||
</template>
|
||||
</q-table>
|
||||
</div>
|
||||
</q-card>
|
||||
</div>
|
||||
</q-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import mixins from "@/mixins/mixins";
|
||||
import ClientsForm from "@/components/modals/clients/ClientsForm";
|
||||
import SitesForm from "@/components/modals/clients/SitesForm";
|
||||
import DeleteClient from "@/components/modals/clients/DeleteClient";
|
||||
import SitesTable from "@/components/modals/clients/SitesTable";
|
||||
|
||||
export default {
|
||||
name: "ClientsManager",
|
||||
mixins: [mixins],
|
||||
data() {
|
||||
return {
|
||||
clients: [],
|
||||
columns: [
|
||||
{ name: "name", label: "Name", field: "name", align: "left" },
|
||||
{ name: "sites", label: "Sites", field: "sites", align: "left" },
|
||||
],
|
||||
pagination: {
|
||||
rowsPerPage: 0,
|
||||
sortBy: "name",
|
||||
descending: true,
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
getClients() {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.get("clients/clients/")
|
||||
.then(r => {
|
||||
this.clients = r.data;
|
||||
this.$q.loading.hide();
|
||||
})
|
||||
.catch(e => {
|
||||
this.$q.loading.hide();
|
||||
this.notifyError("Unable to get Clients.");
|
||||
});
|
||||
},
|
||||
showClientDeleteModal(client) {
|
||||
this.$q
|
||||
.dialog({
|
||||
component: DeleteClient,
|
||||
parent: this,
|
||||
object: client,
|
||||
type: "client",
|
||||
})
|
||||
.onOk(() => {
|
||||
this.getClients();
|
||||
});
|
||||
},
|
||||
showEditClient(client) {
|
||||
this.$q
|
||||
.dialog({
|
||||
component: ClientsForm,
|
||||
parent: this,
|
||||
client: client,
|
||||
})
|
||||
.onOk(() => {
|
||||
this.getClients();
|
||||
});
|
||||
},
|
||||
showAddClient() {
|
||||
this.$q
|
||||
.dialog({
|
||||
component: ClientsForm,
|
||||
parent: this,
|
||||
})
|
||||
.onOk(() => {
|
||||
this.getClients();
|
||||
});
|
||||
},
|
||||
showAddSite(client) {
|
||||
this.$q
|
||||
.dialog({
|
||||
component: SitesForm,
|
||||
parent: this,
|
||||
client: client.id,
|
||||
})
|
||||
.onOk(() => {
|
||||
this.getClients();
|
||||
});
|
||||
},
|
||||
showSitesTable(client) {
|
||||
this.$q.dialog({
|
||||
component: SitesTable,
|
||||
parent: this,
|
||||
client: client,
|
||||
});
|
||||
},
|
||||
show() {
|
||||
this.$refs.dialog.show();
|
||||
},
|
||||
hide() {
|
||||
this.$refs.dialog.hide();
|
||||
},
|
||||
onHide() {
|
||||
this.$emit("hide");
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getClients();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
92
src/components/CustomField.vue
Normal file
92
src/components/CustomField.vue
Normal file
@@ -0,0 +1,92 @@
|
||||
<template>
|
||||
<q-input
|
||||
v-if="field.type === 'text'"
|
||||
ref="input"
|
||||
outlined
|
||||
dense
|
||||
:label="field.name"
|
||||
type="text"
|
||||
:value="value"
|
||||
@input="value => $emit('input', value)"
|
||||
:rules="[...validationRules]"
|
||||
reactive-rules
|
||||
/>
|
||||
|
||||
<q-input
|
||||
v-else-if="field.type === 'number'"
|
||||
ref="input"
|
||||
outlined
|
||||
dense
|
||||
:label="field.name"
|
||||
type="number"
|
||||
:value="value"
|
||||
@input="value => $emit('input', value)"
|
||||
:rules="[...validationRules]"
|
||||
reactive-rules
|
||||
/>
|
||||
|
||||
<q-toggle
|
||||
v-else-if="field.type === 'checkbox'"
|
||||
:label="field.name"
|
||||
:value="value"
|
||||
@input="value => $emit('input', value)"
|
||||
/>
|
||||
|
||||
<q-input v-else-if="field.type === 'datetime'" outlined dense :value="value" @input="value => $emit('input', value)">
|
||||
<template v-slot:append>
|
||||
<q-icon name="event" class="cursor-pointer">
|
||||
<q-popup-proxy transition-show="scale" transition-hide="scale">
|
||||
<q-date v-model="value" mask="YYYY-MM-DD HH:mm">
|
||||
<div class="row items-center justify-end">
|
||||
<q-btn v-close-popup label="Close" color="primary" flat />
|
||||
</div>
|
||||
</q-date>
|
||||
</q-popup-proxy>
|
||||
</q-icon>
|
||||
<q-icon name="access_time" class="cursor-pointer">
|
||||
<q-popup-proxy transition-show="scale" transition-hide="scale">
|
||||
<q-time v-model="value" mask="YYYY-MM-DD HH:mm">
|
||||
<div class="row items-center justify-end">
|
||||
<q-btn v-close-popup label="Close" color="primary" flat />
|
||||
</div>
|
||||
</q-time>
|
||||
</q-popup-proxy>
|
||||
</q-icon>
|
||||
</template>
|
||||
</q-input>
|
||||
|
||||
<q-select
|
||||
v-else-if="field.type === 'single' || field.type === 'multiple'"
|
||||
:value="value"
|
||||
@input="value => $emit('input', value)"
|
||||
outlined
|
||||
dense
|
||||
:options="field.options"
|
||||
:multiple="field.type === 'multiple'"
|
||||
:rules="[...validationRules]"
|
||||
reactive-rules
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "CustomField",
|
||||
props: ["field", "value"],
|
||||
methods: {
|
||||
validate(...args) {
|
||||
return this.$refs.input.validate(...args);
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
validationRules() {
|
||||
const rules = [];
|
||||
|
||||
if (this.field.required) {
|
||||
rules.push(val => !!val || `${this.field.name} is required`);
|
||||
}
|
||||
|
||||
return rules;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -12,28 +12,11 @@
|
||||
</q-item-section>
|
||||
<q-menu anchor="top right" self="top left">
|
||||
<q-list dense style="min-width: 100px">
|
||||
<q-item clickable v-close-popup @click="showClientsFormModal('client', 'add')">
|
||||
<q-item-section>Add Client</q-item-section>
|
||||
<q-item clickable v-close-popup @click="showAddClientModal">
|
||||
<q-item-section>Client</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable v-close-popup @click="showClientsFormModal('site', 'add')">
|
||||
<q-item-section>Add Site</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-menu>
|
||||
</q-item>
|
||||
|
||||
<q-item clickable>
|
||||
<q-item-section>Delete</q-item-section>
|
||||
<q-item-section side>
|
||||
<q-icon name="keyboard_arrow_right" />
|
||||
</q-item-section>
|
||||
<q-menu anchor="top right" self="top left">
|
||||
<q-list dense style="min-width: 100px">
|
||||
<q-item clickable v-close-popup @click="showClientsFormModal('client', 'delete')">
|
||||
<q-item-section>Delete Client</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable v-close-popup @click="showClientsFormModal('site', 'delete')">
|
||||
<q-item-section>Delete Site</q-item-section>
|
||||
<q-item clickable v-close-popup @click="showAddSiteModal">
|
||||
<q-item-section>Site</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-menu>
|
||||
@@ -51,19 +34,6 @@
|
||||
</q-list>
|
||||
</q-menu>
|
||||
</q-btn>
|
||||
<!-- edit -->
|
||||
<q-btn size="md" dense no-caps flat label="Edit">
|
||||
<q-menu>
|
||||
<q-list dense style="min-width: 100px">
|
||||
<q-item clickable v-close-popup @click="showClientsFormModal('client', 'edit')">
|
||||
<q-item-section>Edit Clients</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable v-close-popup @click="showClientsFormModal('site', 'edit')">
|
||||
<q-item-section>Edit Sites</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-menu>
|
||||
</q-btn>
|
||||
<!-- view -->
|
||||
<q-btn size="md" dense no-caps flat label="View">
|
||||
<q-menu auto-close>
|
||||
@@ -95,6 +65,10 @@
|
||||
<q-btn size="md" dense no-caps flat label="Settings">
|
||||
<q-menu auto-close>
|
||||
<q-list dense style="min-width: 100px">
|
||||
<!-- clients manager -->
|
||||
<q-item clickable v-close-popup @click="showClientsManager">
|
||||
<q-item-section>Clients Manager</q-item-section>
|
||||
</q-item>
|
||||
<!-- script manager -->
|
||||
<q-item clickable v-close-popup @click="showScriptManager = true">
|
||||
<q-item-section>Script Manager</q-item-section>
|
||||
@@ -143,14 +117,6 @@
|
||||
</q-btn>
|
||||
</q-btn-group>
|
||||
<q-space />
|
||||
<!-- client form modal -->
|
||||
<q-dialog v-model="showClientFormModal" @hide="closeClientsFormModal">
|
||||
<ClientsForm @close="closeClientsFormModal" :op="clientOp" @edited="edited" />
|
||||
</q-dialog>
|
||||
<!-- site form modal -->
|
||||
<q-dialog v-model="showSiteFormModal" @hide="closeClientsFormModal">
|
||||
<SitesForm @close="closeClientsFormModal" :op="clientOp" @edited="edited" />
|
||||
</q-dialog>
|
||||
<!-- edit core settings modal -->
|
||||
<q-dialog v-model="showEditCoreSettingsModal">
|
||||
<EditCoreSettings @close="showEditCoreSettingsModal = false" />
|
||||
@@ -220,6 +186,7 @@
|
||||
<script>
|
||||
import LogModal from "@/components/modals/logs/LogModal";
|
||||
import PendingActions from "@/components/modals/logs/PendingActions";
|
||||
import ClientsManager from "@/components/ClientsManager";
|
||||
import ClientsForm from "@/components/modals/clients/ClientsForm";
|
||||
import SitesForm from "@/components/modals/clients/SitesForm";
|
||||
import UpdateAgents from "@/components/modals/agents/UpdateAgents";
|
||||
@@ -240,8 +207,6 @@ export default {
|
||||
components: {
|
||||
LogModal,
|
||||
PendingActions,
|
||||
ClientsForm,
|
||||
SitesForm,
|
||||
UpdateAgents,
|
||||
ScriptManager,
|
||||
EditCoreSettings,
|
||||
@@ -253,13 +218,9 @@ export default {
|
||||
Deployment,
|
||||
ServerMaintenance,
|
||||
},
|
||||
props: ["clients"],
|
||||
data() {
|
||||
return {
|
||||
showServerMaintenance: false,
|
||||
showClientFormModal: false,
|
||||
showSiteFormModal: false,
|
||||
clientOp: null,
|
||||
showUpdateAgentsModal: false,
|
||||
showEditCoreSettingsModal: false,
|
||||
showAdminManager: false,
|
||||
@@ -275,20 +236,6 @@ export default {
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
showClientsFormModal(type, op) {
|
||||
this.clientOp = op;
|
||||
|
||||
if (type === "client") {
|
||||
this.showClientFormModal = true;
|
||||
} else if (type === "site") {
|
||||
this.showSiteFormModal = true;
|
||||
}
|
||||
},
|
||||
closeClientsFormModal() {
|
||||
this.clientOp = null;
|
||||
this.showClientFormModal = null;
|
||||
this.showSiteFormModal = null;
|
||||
},
|
||||
showBulkActionModal(mode) {
|
||||
this.bulkMode = mode;
|
||||
this.showBulkAction = true;
|
||||
@@ -309,6 +256,24 @@ export default {
|
||||
parent: this,
|
||||
});
|
||||
},
|
||||
showClientsManager() {
|
||||
this.$q.dialog({
|
||||
component: ClientsManager,
|
||||
parent: this,
|
||||
});
|
||||
},
|
||||
showAddClientModal() {
|
||||
this.$q.dialog({
|
||||
component: ClientsForm,
|
||||
parent: this,
|
||||
});
|
||||
},
|
||||
showAddSiteModal() {
|
||||
this.$q.dialog({
|
||||
component: SitesForm,
|
||||
parent: this,
|
||||
});
|
||||
},
|
||||
edited() {
|
||||
this.$emit("edited");
|
||||
},
|
||||
|
||||
@@ -131,6 +131,9 @@
|
||||
<q-checkbox v-model="agent.overdue_email_alert" label="Get overdue email alerts" />
|
||||
<q-checkbox v-model="agent.overdue_text_alert" label="Get overdue sms alerts" />
|
||||
</q-card-section>
|
||||
<q-card-section v-for="field in customFields" :key="field.id">
|
||||
<CustomField v-model="custom_fields[field.name]" :field="field" />
|
||||
</q-card-section>
|
||||
</q-tab-panel>
|
||||
<!-- patch -->
|
||||
<q-tab-panel name="patch">
|
||||
@@ -151,13 +154,16 @@
|
||||
import { mapGetters } from "vuex";
|
||||
import mixins from "@/mixins/mixins";
|
||||
import PatchPolicyForm from "@/components/modals/agents/PatchPolicyForm";
|
||||
import CustomField from "@/components/CustomField";
|
||||
|
||||
export default {
|
||||
name: "EditAgent",
|
||||
components: { PatchPolicyForm },
|
||||
components: { PatchPolicyForm, CustomField },
|
||||
mixins: [mixins],
|
||||
data() {
|
||||
return {
|
||||
customFields: [],
|
||||
custom_fields: {},
|
||||
agentLoaded: false,
|
||||
clientsLoaded: false,
|
||||
agent: {},
|
||||
@@ -192,6 +198,14 @@ export default {
|
||||
|
||||
this.agent.client = { label: r.data.client.name, id: r.data.client.id, sites: r.data.client.sites };
|
||||
this.agentLoaded = true;
|
||||
|
||||
for (let field of this.customFields) {
|
||||
const value = r.data.custom_fields.find(value => value.field === field.id);
|
||||
|
||||
if (!!value) this.$set(this.custom_fields, field.name, value.value);
|
||||
else if (!!field.default_value) this.$set(this.custom_fields, field.name, field.default_value);
|
||||
else this.$set(this.custom_fields, field.name, "");
|
||||
}
|
||||
});
|
||||
},
|
||||
getClientsSites() {
|
||||
@@ -219,7 +233,10 @@ export default {
|
||||
}
|
||||
|
||||
this.$axios
|
||||
.patch("/agents/editagent/", this.agent)
|
||||
.patch("/agents/editagent/", {
|
||||
...this.agent,
|
||||
custom_fields: this.formatCustomFields(this.customFields, this.custom_fields),
|
||||
})
|
||||
.then(r => {
|
||||
this.$emit("close");
|
||||
this.$emit("edited");
|
||||
@@ -237,6 +254,10 @@ export default {
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// Get custom fields
|
||||
this.getCustomFields("agent").then(r => {
|
||||
this.customFields = r.data;
|
||||
});
|
||||
this.getAgentInfo();
|
||||
this.getClientsSites();
|
||||
},
|
||||
|
||||
@@ -1,189 +1,180 @@
|
||||
<template>
|
||||
<q-card style="min-width: 400px">
|
||||
<q-card-section class="row">
|
||||
<q-card-actions align="left">
|
||||
<div class="text-h6">{{ modalTitle }}</div>
|
||||
</q-card-actions>
|
||||
<q-space />
|
||||
<q-card-actions align="right">
|
||||
<q-btn v-close-popup flat round dense icon="close" />
|
||||
</q-card-actions>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<q-form @submit.prevent="submit">
|
||||
<q-card-section v-if="op === 'edit' || op === 'delete'">
|
||||
<q-select
|
||||
:rules="[val => !!val || '*Required']"
|
||||
outlined
|
||||
options-dense
|
||||
label="Select client"
|
||||
v-model="selected_client"
|
||||
:options="client_options"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section v-if="op === 'add'">
|
||||
<q-input
|
||||
outlined
|
||||
v-model="client.name"
|
||||
label="Client"
|
||||
:rules="[val => (val && val.length > 0) || '*Required']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section v-if="op === 'add' || op === 'edit'">
|
||||
<q-input
|
||||
v-if="op === 'add'"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
outlined
|
||||
v-model="client.site"
|
||||
label="Default first site"
|
||||
/>
|
||||
<q-input
|
||||
v-else-if="op === 'edit'"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
outlined
|
||||
v-model="client.name"
|
||||
label="Rename client"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-actions align="left">
|
||||
<q-btn
|
||||
:label="capitalize(op)"
|
||||
:color="op === 'delete' ? 'negative' : 'primary'"
|
||||
type="submit"
|
||||
class="full-width"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-form>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
<q-dialog ref="dialog" @hide="onHide">
|
||||
<q-card class="q-dialog-plugin" style="width: 60vw">
|
||||
<q-bar>
|
||||
{{ title }}
|
||||
<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-card-section>
|
||||
<q-form @submit.prevent="submit">
|
||||
<q-card-section>
|
||||
<q-input
|
||||
outlined
|
||||
dense
|
||||
v-model="localClient.name"
|
||||
label="Name"
|
||||
:rules="[val => (val && val.length > 0) || '*Required']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section v-if="!editing">
|
||||
<q-input
|
||||
:rules="[val => !!val || '*Required']"
|
||||
outlined
|
||||
dense
|
||||
v-model="site.name"
|
||||
label="Default first site"
|
||||
/>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section v-for="field in customFields" :key="field.id">
|
||||
<CustomField v-model="custom_fields[field.name]" :field="field" />
|
||||
</q-card-section>
|
||||
<q-card-actions align="right">
|
||||
<q-btn dense flat label="Cancel" v-close-popup />
|
||||
<q-btn dense flat label="Save" color="primary" type="submit" />
|
||||
</q-card-actions>
|
||||
</q-form>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CustomField from "@/components/CustomField";
|
||||
import mixins from "@/mixins/mixins";
|
||||
export default {
|
||||
name: "ClientsForm",
|
||||
components: {
|
||||
CustomField,
|
||||
},
|
||||
mixins: [mixins],
|
||||
props: {
|
||||
op: !String,
|
||||
clientpk: Number,
|
||||
client: !Object,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
client_options: [],
|
||||
selected_client: {},
|
||||
client: {
|
||||
id: null,
|
||||
customFields: [],
|
||||
site: {
|
||||
name: "",
|
||||
site: "",
|
||||
},
|
||||
localClient: {
|
||||
name: "",
|
||||
},
|
||||
custom_fields: {},
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
selected_client(newClient, oldClient) {
|
||||
this.client.id = newClient.value;
|
||||
this.client.name = newClient.label;
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
modalTitle() {
|
||||
if (this.op === "add") return "Add Client";
|
||||
if (this.op === "edit") return "Edit Client";
|
||||
if (this.op === "delete") return "Delete Client";
|
||||
title() {
|
||||
return this.editing ? "Edit Client" : "Add Client";
|
||||
},
|
||||
editing() {
|
||||
return !!this.client;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
submit() {
|
||||
if (this.op === "add") this.addClient();
|
||||
if (this.op === "edit") this.editClient();
|
||||
if (this.op === "delete") this.deleteClient();
|
||||
},
|
||||
getClients() {
|
||||
this.$axios.get("/clients/clients/").then(r => {
|
||||
this.client_options = r.data.map(client => ({ label: client.name, value: client.id }));
|
||||
|
||||
if (this.clientpk !== undefined && this.clientpk !== null) {
|
||||
let client = this.client_options.find(client => client.value === this.clientpk);
|
||||
|
||||
this.selected_client = client;
|
||||
} else {
|
||||
this.selected_client = this.client_options[0];
|
||||
}
|
||||
});
|
||||
if (!this.editing) this.addClient();
|
||||
else this.editClient();
|
||||
},
|
||||
addClient() {
|
||||
this.$q.loading.show();
|
||||
const data = {
|
||||
client: this.client.name,
|
||||
site: this.client.site,
|
||||
client: this.localClient,
|
||||
site: this.site,
|
||||
custom_fields: this.formatCustomFields(this.customFields, this.custom_fields),
|
||||
};
|
||||
this.$axios
|
||||
.post("/clients/clients/", data)
|
||||
.then(r => {
|
||||
this.$emit("close");
|
||||
this.$store.dispatch("loadTree");
|
||||
this.$store.dispatch("getUpdatedSites");
|
||||
this.refreshDashboardTree();
|
||||
this.$q.loading.hide();
|
||||
this.onOk();
|
||||
this.notifySuccess(r.data);
|
||||
})
|
||||
.catch(e => {
|
||||
this.$q.loading.hide();
|
||||
if (e.response.data.client) {
|
||||
this.notifyError(e.response.data.client);
|
||||
if (e.response.data.name) {
|
||||
this.notifyError(e.response.data.name);
|
||||
} else {
|
||||
this.notifyError(e.response.data.non_field_errors);
|
||||
this.notifyError(e.response.data);
|
||||
}
|
||||
});
|
||||
},
|
||||
editClient() {
|
||||
this.$q.loading.show();
|
||||
const data = {
|
||||
id: this.client.id,
|
||||
name: this.client.name,
|
||||
client: this.localClient,
|
||||
custom_fields: this.formatCustomFields(this.customFields, this.custom_fields),
|
||||
};
|
||||
|
||||
this.$axios
|
||||
.put(`/clients/${this.client.id}/client/`, this.client)
|
||||
.put(`/clients/${this.client.id}/client/`, data)
|
||||
.then(r => {
|
||||
this.$emit("edited");
|
||||
this.$emit("close");
|
||||
this.refreshDashboardTree();
|
||||
this.onOk();
|
||||
this.$q.loading.hide();
|
||||
this.notifySuccess(r.data);
|
||||
})
|
||||
.catch(e => {
|
||||
this.$q.loading.hide();
|
||||
if (e.response.data.client) {
|
||||
this.notifyError(e.response.data.client);
|
||||
if (e.response.data.name) {
|
||||
this.notifyError(e.response.data.name);
|
||||
} else {
|
||||
this.notifyError(e.response.data.non_field_errors);
|
||||
this.notifyError(e.response.data);
|
||||
}
|
||||
});
|
||||
},
|
||||
deleteClient() {
|
||||
this.$q
|
||||
.dialog({
|
||||
title: "Are you sure?",
|
||||
message: `Delete client ${this.client.name}`,
|
||||
cancel: true,
|
||||
ok: { label: "Delete", color: "negative" },
|
||||
getClient() {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.get(`/clients/${this.client.id}/client/`)
|
||||
.then(r => {
|
||||
this.$q.loading.hide();
|
||||
this.localClient.name = r.data.name;
|
||||
|
||||
for (let field of this.customFields) {
|
||||
const value = r.data.custom_fields.find(value => value.field === field.id);
|
||||
|
||||
if (!!value) this.$set(this.custom_fields, field.name, value.value);
|
||||
else if (!!field.default_value) this.$set(this.custom_fields, field.name, field.default_value);
|
||||
else this.$set(this.custom_fields, field.name, "");
|
||||
}
|
||||
})
|
||||
.onOk(() => {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.delete(`/clients/${this.client.id}/client/`)
|
||||
.then(r => {
|
||||
this.$q.loading.hide();
|
||||
this.$emit("edited");
|
||||
this.$emit("close");
|
||||
this.notifySuccess(r.data);
|
||||
})
|
||||
.catch(e => {
|
||||
this.$q.loading.hide();
|
||||
this.notifyError(e.response.data, 6000);
|
||||
});
|
||||
.catch(e => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
refreshDashboardTree() {
|
||||
this.$store.dispatch("loadTree");
|
||||
this.$store.dispatch("getUpdatedSites");
|
||||
},
|
||||
show() {
|
||||
this.$refs.dialog.show();
|
||||
},
|
||||
hide() {
|
||||
this.$refs.dialog.hide();
|
||||
},
|
||||
onHide() {
|
||||
this.$emit("hide");
|
||||
},
|
||||
onOk() {
|
||||
this.$emit("ok");
|
||||
this.hide();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (this.op !== "add") this.getClients();
|
||||
// Get custom fields
|
||||
this.getCustomFields("client").then(r => {
|
||||
this.customFields = r.data;
|
||||
});
|
||||
|
||||
// Copy client prop locally
|
||||
if (this.editing) {
|
||||
this.getClient();
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
161
src/components/modals/clients/DeleteClient.vue
Normal file
161
src/components/modals/clients/DeleteClient.vue
Normal file
@@ -0,0 +1,161 @@
|
||||
<template>
|
||||
<q-dialog ref="dialog" @hide="onHide">
|
||||
<q-card class="q-dialog-plugin">
|
||||
<q-bar>
|
||||
Delete {{ object.name }}
|
||||
<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-form @submit="submit">
|
||||
<q-card-section>
|
||||
<q-select
|
||||
label="Site to move agents to"
|
||||
dense
|
||||
options-dense
|
||||
outlined
|
||||
v-model="selectedSite"
|
||||
:options="siteOptions"
|
||||
map-options
|
||||
emit-value
|
||||
:rules="[val => !!val || 'Select the site that the agents should be moved to']"
|
||||
>
|
||||
<template v-slot:option="scope">
|
||||
<q-item v-if="!scope.opt.category" v-bind="scope.itemProps" v-on="scope.itemEvents" class="q-pl-lg">
|
||||
<q-item-section>
|
||||
<q-item-label v-html="scope.opt.label"></q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item-label v-if="scope.opt.category" v-bind="scope.itemProps" header class="q-pa-sm">{{
|
||||
scope.opt.category
|
||||
}}</q-item-label>
|
||||
</template>
|
||||
</q-select>
|
||||
</q-card-section>
|
||||
<q-card-actions align="right">
|
||||
<q-btn dense flat label="Cancel" v-close-popup />
|
||||
<q-btn dense flat label="Delete" color="negative" type="submit" />
|
||||
</q-card-actions>
|
||||
</q-form>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import mixins from "@/mixins/mixins";
|
||||
export default {
|
||||
name: "DeleteClient",
|
||||
mixins: [mixins],
|
||||
props: {
|
||||
object: !Object,
|
||||
type: !String,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
siteOptions: [],
|
||||
selectedSite: null,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
submit() {
|
||||
if (this.type === "client") this.deleteClient();
|
||||
else this.deleteSite();
|
||||
},
|
||||
deleteClient() {
|
||||
this.$q
|
||||
.dialog({
|
||||
title: "Are you sure?",
|
||||
message: `Delete client ${this.object.name}. Agents from all sites will be moved to the selected site`,
|
||||
cancel: true,
|
||||
ok: { label: "Delete", color: "negative" },
|
||||
})
|
||||
.onOk(() => {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.delete(`/clients/${this.object.id}/${this.selectedSite}/`)
|
||||
.then(r => {
|
||||
this.refreshDashboardTree();
|
||||
this.$q.loading.hide();
|
||||
this.onOk();
|
||||
this.notifySuccess(r.data);
|
||||
})
|
||||
.catch(e => {
|
||||
this.$q.loading.hide();
|
||||
this.notifyError(e.response.data, 6000);
|
||||
});
|
||||
});
|
||||
},
|
||||
deleteSite() {
|
||||
this.$q
|
||||
.dialog({
|
||||
title: "Are you sure?",
|
||||
message: `Delete site ${this.object.name}. Agents from all sites will be moved to the selected site`,
|
||||
cancel: true,
|
||||
ok: { label: "Delete", color: "negative" },
|
||||
})
|
||||
.onOk(() => {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.delete(`/clients/sites/${this.object.id}/${this.selectedSite}/`)
|
||||
.then(r => {
|
||||
this.refreshDashboardTree();
|
||||
this.$q.loading.hide();
|
||||
this.onOk();
|
||||
this.notifySuccess(r.data);
|
||||
})
|
||||
.catch(e => {
|
||||
this.$q.loading.hide();
|
||||
this.notifyError(e.response.data, 6000);
|
||||
});
|
||||
});
|
||||
},
|
||||
getSites() {
|
||||
this.$axios.get("/clients/clients/").then(r => {
|
||||
r.data.forEach(client => {
|
||||
// remove client that is being deleted from options
|
||||
if (this.type === "client") {
|
||||
if (client.id !== this.object.id) {
|
||||
this.siteOptions.push({ category: client.name });
|
||||
|
||||
client.sites.forEach(site => {
|
||||
this.siteOptions.push({ label: site.name, value: site.id });
|
||||
});
|
||||
}
|
||||
} else {
|
||||
this.siteOptions.push({ category: client.name });
|
||||
|
||||
client.sites.forEach(site => {
|
||||
if (site.id !== this.object.id) {
|
||||
this.siteOptions.push({ label: site.name, value: site.id });
|
||||
} else if (client.sites.length === 1) {
|
||||
this.siteOptions.pop();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
refreshDashboardTree() {
|
||||
this.$store.dispatch("loadTree");
|
||||
this.$store.dispatch("getUpdatedSites");
|
||||
},
|
||||
show() {
|
||||
this.$refs.dialog.show();
|
||||
},
|
||||
hide() {
|
||||
this.$refs.dialog.hide();
|
||||
},
|
||||
onHide() {
|
||||
this.$emit("hide");
|
||||
},
|
||||
onOk() {
|
||||
this.$emit("ok");
|
||||
this.hide();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getSites();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1,197 +1,195 @@
|
||||
<template>
|
||||
<q-card style="min-width: 400px">
|
||||
<q-card-section class="row">
|
||||
<q-card-actions align="left">
|
||||
<div class="text-h6">{{ modalTitle }}</div>
|
||||
</q-card-actions>
|
||||
<q-space />
|
||||
<q-card-actions align="right">
|
||||
<q-btn v-close-popup flat round dense icon="close" />
|
||||
</q-card-actions>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<q-form @submit.prevent="submit">
|
||||
<q-card-section>
|
||||
<q-select
|
||||
:rules="[val => !!val || '*Required']"
|
||||
outlined
|
||||
options-dense
|
||||
label="Select client"
|
||||
v-model="selected_client"
|
||||
:options="client_options"
|
||||
@input="op === 'edit' || op === 'delete' ? (selected_site = sites[0]) : () => {}"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section v-if="op === 'edit' || op === 'delete'">
|
||||
<q-select
|
||||
:rules="[val => !!val || '*Required']"
|
||||
outlined
|
||||
options-dense
|
||||
label="Select site"
|
||||
v-model="selected_site"
|
||||
:options="sites"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section v-if="op === 'add' || op === 'edit'">
|
||||
<q-input
|
||||
v-if="op === 'add'"
|
||||
outlined
|
||||
v-model="site.name"
|
||||
label="Site"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
/>
|
||||
<q-input
|
||||
v-else-if="op === 'edit'"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
outlined
|
||||
v-model="site.name"
|
||||
label="Rename site"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-actions align="left">
|
||||
<q-btn
|
||||
:label="capitalize(op)"
|
||||
:color="op === 'delete' ? 'negative' : 'primary'"
|
||||
type="submit"
|
||||
class="full-width"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-form>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
<q-dialog ref="dialog" @hide="onHide">
|
||||
<q-card class="q-dialog-plugin" style="width: 60vw">
|
||||
<q-bar>
|
||||
{{ title }}
|
||||
<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-card-section>
|
||||
<q-form @submit.prevent="submit">
|
||||
<q-card-section>
|
||||
<q-select
|
||||
v-model="localSite.client"
|
||||
label="Client"
|
||||
:options="clientOptions"
|
||||
outlined
|
||||
dense
|
||||
options-dense
|
||||
map-options
|
||||
emit-value
|
||||
:rules="[val => !!val || 'Client is required']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<q-input
|
||||
:rules="[val => !!val || 'Name is required']"
|
||||
outlined
|
||||
dense
|
||||
v-model="localSite.name"
|
||||
label="Name"
|
||||
/>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section v-for="field in customFields" :key="field.id">
|
||||
<CustomField v-model="custom_fields[field.name]" :field="field" />
|
||||
</q-card-section>
|
||||
|
||||
<q-card-actions align="right">
|
||||
<q-btn dense flat label="Cancel" v-close-popup />
|
||||
<q-btn dense flat label="Save" color="primary" type="submit" />
|
||||
</q-card-actions>
|
||||
</q-form>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CustomField from "@/components/CustomField";
|
||||
import mixins from "@/mixins/mixins";
|
||||
export default {
|
||||
name: "SitesForm",
|
||||
name: "ClientsForm",
|
||||
components: {
|
||||
CustomField,
|
||||
},
|
||||
mixins: [mixins],
|
||||
props: {
|
||||
op: !String,
|
||||
sitepk: Number,
|
||||
site: !Object,
|
||||
client: !Number,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
client_options: [],
|
||||
selected_client: null,
|
||||
selected_site: null,
|
||||
site: {
|
||||
id: null,
|
||||
customFields: [],
|
||||
clientOptions: [],
|
||||
localSite: {
|
||||
client: null,
|
||||
name: "",
|
||||
},
|
||||
custom_fields: {},
|
||||
};
|
||||
},
|
||||
watch: {
|
||||
selected_site(newSite, oldSite) {
|
||||
this.site.id = newSite.value;
|
||||
this.site.name = newSite.label;
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
sites() {
|
||||
return !!this.selected_client ? this.formatSiteOptions(this.selected_client.sites) : [];
|
||||
title() {
|
||||
return this.editing ? "Edit Site" : "Add Site";
|
||||
},
|
||||
modalTitle() {
|
||||
if (this.op === "add") return "Add Site";
|
||||
if (this.op === "edit") return "Edit Site";
|
||||
if (this.op === "delete") return "Delete Site";
|
||||
editing() {
|
||||
return !!this.site;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
submit() {
|
||||
if (this.op === "add") this.addSite();
|
||||
if (this.op === "edit") this.editSite();
|
||||
if (this.op === "delete") this.deleteSite();
|
||||
},
|
||||
getClients() {
|
||||
this.$axios.get("/clients/clients/").then(r => {
|
||||
this.client_options = this.formatClientOptions(r.data);
|
||||
|
||||
if (this.sitepk !== undefined && this.sitepk !== null) {
|
||||
this.client_options.forEach(client => {
|
||||
let site = client.sites.find(site => site.id === this.sitepk);
|
||||
|
||||
if (site !== undefined) {
|
||||
this.selected_client = client;
|
||||
this.selected_site = { value: site.id, label: site.name };
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.selected_client = this.client_options[0];
|
||||
if (this.op !== "add") this.selected_site = this.sites[0];
|
||||
}
|
||||
});
|
||||
if (!this.editing) this.addSite();
|
||||
else this.editSite();
|
||||
},
|
||||
addSite() {
|
||||
this.$q.loading.show();
|
||||
|
||||
const data = {
|
||||
client: this.selected_client.value,
|
||||
name: this.site.name,
|
||||
site: this.localSite,
|
||||
custom_fields: this.formatCustomFields(this.customFields, this.custom_fields),
|
||||
};
|
||||
|
||||
this.$axios
|
||||
.post("/clients/sites/", data)
|
||||
.then(() => {
|
||||
this.$emit("close");
|
||||
this.$store.dispatch("loadTree");
|
||||
.then(r => {
|
||||
this.refreshDashboardTree();
|
||||
this.$q.loading.hide();
|
||||
this.notifySuccess(`Site ${this.site.name} was added!`);
|
||||
this.onOk();
|
||||
this.notifySuccess(r.data);
|
||||
})
|
||||
.catch(e => {
|
||||
this.$q.loading.hide();
|
||||
this.notifyError(e.response.data.non_field_errors);
|
||||
if (e.response.data.name) {
|
||||
this.notifyError(e.response.data.name);
|
||||
} else {
|
||||
this.notifyError(e.response.data);
|
||||
}
|
||||
});
|
||||
},
|
||||
editSite() {
|
||||
this.$q.loading.show();
|
||||
|
||||
const data = {
|
||||
id: this.site.id,
|
||||
name: this.site.name,
|
||||
client: this.selected_client.value,
|
||||
site: this.localSite,
|
||||
custom_fields: this.formatCustomFields(this.customFields, this.custom_fields),
|
||||
};
|
||||
|
||||
this.$axios
|
||||
.put(`/clients/${this.site.id}/site/`, data)
|
||||
.then(() => {
|
||||
this.$emit("edited");
|
||||
this.$emit("close");
|
||||
.put(`/clients/sites/${this.site.id}/`, data)
|
||||
.then(r => {
|
||||
this.refreshDashboardTree();
|
||||
this.onOk();
|
||||
this.$q.loading.hide();
|
||||
this.notifySuccess("Site was edited");
|
||||
this.notifySuccess(r.data);
|
||||
})
|
||||
.catch(e => {
|
||||
this.$q.loading.hide();
|
||||
this.notifyError(e.response.data.non_field_errors);
|
||||
if (e.response.data.name) {
|
||||
this.notifyError(e.response.data.name);
|
||||
} else {
|
||||
this.notifyError(e.response.data);
|
||||
}
|
||||
});
|
||||
},
|
||||
deleteSite() {
|
||||
this.$q
|
||||
.dialog({
|
||||
title: "Are you sure?",
|
||||
message: `Delete site ${this.site.name}`,
|
||||
cancel: true,
|
||||
ok: { label: "Delete", color: "negative" },
|
||||
getSite() {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.get(`/clients/sites/${this.site.id}/`)
|
||||
.then(r => {
|
||||
this.$q.loading.hide();
|
||||
this.localSite.name = r.data.name;
|
||||
this.localSite.client = r.data.client;
|
||||
|
||||
for (let field of this.customFields) {
|
||||
const value = r.data.custom_fields.find(value => value.field === field.id);
|
||||
|
||||
if (!!value) this.$set(this.custom_fields, field.name, value.value);
|
||||
else if (!!field.default_value) this.$set(this.custom_fields, field.name, field.default_value);
|
||||
else this.$set(this.custom_fields, field.name, "");
|
||||
}
|
||||
})
|
||||
.onOk(() => {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.delete(`/clients/${this.site.id}/site/`)
|
||||
.then(r => {
|
||||
this.$emit("edited");
|
||||
this.$emit("close");
|
||||
this.$q.loading.hide();
|
||||
this.notifySuccess(r.data);
|
||||
})
|
||||
.catch(e => {
|
||||
this.$q.loading.hide();
|
||||
this.notifyError(e.response.data, 6000);
|
||||
});
|
||||
.catch(e => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
refreshDashboardTree() {
|
||||
this.$store.dispatch("loadTree");
|
||||
this.$store.dispatch("getUpdatedSites");
|
||||
},
|
||||
getClients() {
|
||||
this.$axios.get("/clients/clients/").then(r => {
|
||||
r.data.forEach(client => {
|
||||
this.clientOptions.push({ label: client.name, value: client.id });
|
||||
});
|
||||
});
|
||||
},
|
||||
show() {
|
||||
this.$refs.dialog.show();
|
||||
},
|
||||
hide() {
|
||||
this.$refs.dialog.hide();
|
||||
},
|
||||
onHide() {
|
||||
this.$emit("hide");
|
||||
},
|
||||
onOk() {
|
||||
this.$emit("ok");
|
||||
this.hide();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getClients();
|
||||
|
||||
// Get custom fields
|
||||
this.getCustomFields("site").then(r => {
|
||||
this.customFields = r.data;
|
||||
});
|
||||
|
||||
// Copy site prop locally
|
||||
if (this.editing) {
|
||||
this.getSite();
|
||||
} else {
|
||||
if (this.client) this.localSite.client = this.client;
|
||||
}
|
||||
},
|
||||
};
|
||||
</script>
|
||||
152
src/components/modals/clients/SitesTable.vue
Normal file
152
src/components/modals/clients/SitesTable.vue
Normal file
@@ -0,0 +1,152 @@
|
||||
<template>
|
||||
<q-dialog ref="dialog" @hide="onHide">
|
||||
<div class="q-dialog-plugin" style="width: 60vw; max-width: 60vw">
|
||||
<q-card>
|
||||
<q-bar>
|
||||
<q-btn @click="getSites" class="q-mr-sm" dense flat push icon="refresh" />Sites for {{ client.name }}
|
||||
<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>
|
||||
<div class="q-pa-sm" style="min-height: 40vh; max-height: 40vh">
|
||||
<div class="q-gutter-sm">
|
||||
<q-btn label="New" dense flat push unelevated no-caps icon="add" @click="showAddSite" />
|
||||
</div>
|
||||
<q-table
|
||||
dense
|
||||
:data="sites"
|
||||
:columns="columns"
|
||||
:pagination.sync="pagination"
|
||||
row-key="id"
|
||||
binary-state-sort
|
||||
hide-pagination
|
||||
virtual-scroll
|
||||
:rows-per-page-options="[0]"
|
||||
no-data-label="No Sites"
|
||||
>
|
||||
<!-- body slots -->
|
||||
<template v-slot:body="props">
|
||||
<q-tr :props="props" class="cursor-pointer" @dblclick="showEditSite(props.row)">
|
||||
<!-- context menu -->
|
||||
<q-menu context-menu>
|
||||
<q-list dense style="min-width: 200px">
|
||||
<q-item clickable v-close-popup @click="showEditSite(props.row)">
|
||||
<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="showSiteDeleteModal(props.row)">
|
||||
<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>
|
||||
<!-- name -->
|
||||
<q-td>
|
||||
{{ props.row.name }}
|
||||
</q-td>
|
||||
</q-tr>
|
||||
</template>
|
||||
</q-table>
|
||||
</div>
|
||||
</q-card>
|
||||
</div>
|
||||
</q-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import mixins from "@/mixins/mixins";
|
||||
import SitesForm from "@/components/modals/clients/SitesForm";
|
||||
import DeleteClient from "@/components/modals/clients/DeleteClient";
|
||||
|
||||
export default {
|
||||
name: "SitesTable",
|
||||
mixins: [mixins],
|
||||
props: {
|
||||
client: !Object,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
sites: [],
|
||||
columns: [{ name: "name", label: "Name", field: "name", align: "left" }],
|
||||
pagination: {
|
||||
rowsPerPage: 0,
|
||||
sortBy: "name",
|
||||
descending: true,
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
getSites() {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.get(`clients/${this.client.id}/client/`)
|
||||
.then(r => {
|
||||
this.sites = r.data.sites;
|
||||
this.$q.loading.hide();
|
||||
})
|
||||
.catch(e => {
|
||||
this.$q.loading.hide();
|
||||
this.notifyError("Unable to get Sites.");
|
||||
});
|
||||
},
|
||||
showSiteDeleteModal(site) {
|
||||
this.$q
|
||||
.dialog({
|
||||
component: DeleteClient,
|
||||
parent: this,
|
||||
object: site,
|
||||
type: "site",
|
||||
})
|
||||
.onOk(() => {
|
||||
this.getSites();
|
||||
});
|
||||
},
|
||||
showEditSite(site) {
|
||||
this.$q
|
||||
.dialog({
|
||||
component: SitesForm,
|
||||
parent: this,
|
||||
site: site,
|
||||
client: site.client,
|
||||
})
|
||||
.onOk(() => {
|
||||
this.getSites();
|
||||
});
|
||||
},
|
||||
showAddSite() {
|
||||
this.$q
|
||||
.dialog({
|
||||
component: SitesForm,
|
||||
parent: this,
|
||||
client: this.client.id,
|
||||
})
|
||||
.onOk(() => {
|
||||
this.getSites();
|
||||
});
|
||||
},
|
||||
show() {
|
||||
this.$refs.dialog.show();
|
||||
},
|
||||
hide() {
|
||||
this.$refs.dialog.hide();
|
||||
},
|
||||
onHide() {
|
||||
this.$emit("hide");
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getSites();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
116
src/components/modals/coresettings/CustomFields.vue
Normal file
116
src/components/modals/coresettings/CustomFields.vue
Normal file
@@ -0,0 +1,116 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="row">
|
||||
<div class="text-subtitle2">Custom Fields</div>
|
||||
<q-space />
|
||||
<q-btn
|
||||
size="sm"
|
||||
color="grey-5"
|
||||
icon="fas fa-plus"
|
||||
text-color="black"
|
||||
label="Add custom field"
|
||||
@click="addCustomField"
|
||||
/>
|
||||
</div>
|
||||
<hr />
|
||||
<div>
|
||||
<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="client" label="Clients" />
|
||||
<q-tab name="site" label="Sites" />
|
||||
<q-tab name="agent" label="Agents" />
|
||||
</q-tabs>
|
||||
|
||||
<q-separator />
|
||||
<q-scroll-area :thumb-style="thumbStyle" style="height: 50vh">
|
||||
<q-tab-panels v-model="tab" :animated="false">
|
||||
<q-tab-panel name="client">
|
||||
<CustomFieldsTable @refresh="getCustomFields" :data="clientFields" />
|
||||
</q-tab-panel>
|
||||
|
||||
<q-tab-panel name="site">
|
||||
<CustomFieldsTable @refresh="getCustomFields" :data="siteFields" />
|
||||
</q-tab-panel>
|
||||
|
||||
<q-tab-panel name="agent">
|
||||
<CustomFieldsTable @refresh="getCustomFields" :data="agentFields" />
|
||||
</q-tab-panel>
|
||||
</q-tab-panels>
|
||||
</q-scroll-area>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CustomFieldsTable from "@/components/modals/coresettings/CustomFieldsTable";
|
||||
import CustomFieldsForm from "@/components/modals/coresettings/CustomFieldsForm";
|
||||
|
||||
export default {
|
||||
name: "CustomFields",
|
||||
components: {
|
||||
CustomFieldsTable,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tab: "client",
|
||||
customFields: [],
|
||||
thumbStyle: {
|
||||
right: "2px",
|
||||
borderRadius: "5px",
|
||||
backgroundColor: "#027be3",
|
||||
width: "5px",
|
||||
opacity: 0.75,
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
agentFields() {
|
||||
return this.customFields.filter(field => field.model === "agent");
|
||||
},
|
||||
siteFields() {
|
||||
return this.customFields.filter(field => field.model === "site");
|
||||
},
|
||||
clientFields() {
|
||||
return this.customFields.filter(field => field.model === "client");
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getCustomFields() {
|
||||
this.$q.loading.show();
|
||||
|
||||
this.$axios
|
||||
.get(`/core/customfields/`)
|
||||
.then(r => {
|
||||
this.$q.loading.hide();
|
||||
this.customFields = r.data;
|
||||
})
|
||||
.catch(e => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
addCustomField() {
|
||||
this.$q
|
||||
.dialog({
|
||||
component: CustomFieldsForm,
|
||||
parent: this,
|
||||
model: this.tab,
|
||||
})
|
||||
.onOk(() => {
|
||||
this.getCustomFields();
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getCustomFields();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
244
src/components/modals/coresettings/CustomFieldsForm.vue
Normal file
244
src/components/modals/coresettings/CustomFieldsForm.vue
Normal file
@@ -0,0 +1,244 @@
|
||||
<template>
|
||||
<q-dialog ref="dialog" @hide="onHide">
|
||||
<q-card class="q-dialog-plugin" style="width: 60vw">
|
||||
<q-bar>
|
||||
{{ title }}
|
||||
<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-form @submit="submit">
|
||||
<q-card-section>
|
||||
<q-select
|
||||
label="Target"
|
||||
:options="modelOptions"
|
||||
map-options
|
||||
emit-value
|
||||
outlined
|
||||
dense
|
||||
v-model="localField.model"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<q-input label="Name" outlined dense v-model="localField.name" :rules="[val => !!val || '*Required']" />
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<q-select
|
||||
label="Field Type"
|
||||
:options="typeOptions"
|
||||
@input="clear"
|
||||
map-options
|
||||
emit-value
|
||||
outlined
|
||||
dense
|
||||
v-model="localField.type"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section v-if="localField.type === 'single' || localField.type == 'multiple'">
|
||||
<q-select
|
||||
dense
|
||||
label="Input Options (press Enter after typing each option)"
|
||||
filled
|
||||
v-model="localField.options"
|
||||
use-input
|
||||
use-chips
|
||||
multiple
|
||||
hide-dropdown-icon
|
||||
input-debounce="0"
|
||||
new-value-mode="add"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<!-- For datetime field -->
|
||||
<q-input
|
||||
v-if="localField.type === 'datetime'"
|
||||
outlined
|
||||
dense
|
||||
v-model="localField.default_value"
|
||||
:rules="[...defaultValueRules]"
|
||||
reactive-rules
|
||||
>
|
||||
<template v-slot:append>
|
||||
<q-icon name="event" class="cursor-pointer">
|
||||
<q-popup-proxy transition-show="scale" transition-hide="scale">
|
||||
<q-date v-model="localField.default_value" mask="YYYY-MM-DD HH:mm">
|
||||
<div class="row items-center justify-end">
|
||||
<q-btn v-close-popup label="Close" color="primary" flat />
|
||||
</div>
|
||||
</q-date>
|
||||
</q-popup-proxy>
|
||||
</q-icon>
|
||||
<q-icon name="access_time" class="cursor-pointer">
|
||||
<q-popup-proxy transition-show="scale" transition-hide="scale">
|
||||
<q-time v-model="localField.default_value" mask="YYYY-MM-DD HH:mm">
|
||||
<div class="row items-center justify-end">
|
||||
<q-btn v-close-popup label="Close" color="primary" flat />
|
||||
</div>
|
||||
</q-time>
|
||||
</q-popup-proxy>
|
||||
</q-icon>
|
||||
</template>
|
||||
</q-input>
|
||||
|
||||
<!-- For Checkbox -->
|
||||
<q-toggle
|
||||
v-else-if="localField.type == 'checkbox'"
|
||||
label="Default Value"
|
||||
v-model="localField.default_value"
|
||||
color="green"
|
||||
/>
|
||||
|
||||
<!-- For dropdowns -->
|
||||
<q-select
|
||||
v-else-if="localField.type === 'single' || localField.type === 'multiple'"
|
||||
label="Default Value"
|
||||
:options="localField.options"
|
||||
outlined
|
||||
dense
|
||||
:multiple="localField.type === 'multiple'"
|
||||
v-model="localField.default_value"
|
||||
:rules="[...defaultValueRules]"
|
||||
reactive-rules
|
||||
/>
|
||||
|
||||
<!-- For everything else -->
|
||||
<q-input
|
||||
v-else
|
||||
label="Default Value"
|
||||
:type="localField.type === 'text' ? 'text' : 'number'"
|
||||
outlined
|
||||
dense
|
||||
v-model="localField.default_value"
|
||||
:rules="[...defaultValueRules]"
|
||||
reactive-rules
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<q-toggle
|
||||
v-if="localField.type !== 'checkbox'"
|
||||
label="Required"
|
||||
v-model="localField.required"
|
||||
color="green"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-actions align="right">
|
||||
<q-btn flat label="Cancel" v-close-popup />
|
||||
<q-btn flat label="Submit" color="primary" type="submit" />
|
||||
</q-card-actions>
|
||||
</q-form>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import mixins from "@/mixins/mixins";
|
||||
|
||||
export default {
|
||||
name: "CustomFieldsForm",
|
||||
mixins: [mixins],
|
||||
props: { field: Object, model: String },
|
||||
data() {
|
||||
return {
|
||||
localField: {
|
||||
name: "",
|
||||
model: "",
|
||||
type: "",
|
||||
options: [],
|
||||
default_value: "",
|
||||
required: false,
|
||||
},
|
||||
modelOptions: [
|
||||
{ label: "Client", value: "client" },
|
||||
{ label: "Site", value: "site" },
|
||||
{ label: "Agent", value: "agent" },
|
||||
],
|
||||
typeOptions: [
|
||||
{ label: "Text", value: "text" },
|
||||
{ label: "Number", value: "number" },
|
||||
{ label: "Dropdown Single", value: "single" },
|
||||
{ label: "Dropdown Multiple", value: "multiple" },
|
||||
{ label: "DateTime", value: "datetime" },
|
||||
{ label: "Checkbox", value: "checkbox" },
|
||||
],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
title() {
|
||||
return this.editing ? "Edit Custom Field" : "Add Custom Field";
|
||||
},
|
||||
editing() {
|
||||
return !!this.field;
|
||||
},
|
||||
defaultValueRules() {
|
||||
if (this.localField.required) {
|
||||
return [val => !!val || `Default Value needs to be set for required fields`];
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
submit() {
|
||||
this.$q.loading.show();
|
||||
|
||||
let data = {
|
||||
...this.localField,
|
||||
};
|
||||
|
||||
if (this.editing) {
|
||||
this.$axios
|
||||
.put(`/core/customfields/${data.id}/`, data)
|
||||
.then(r => {
|
||||
this.$q.loading.hide();
|
||||
this.onOk();
|
||||
this.notifySuccess("Custom field edited!");
|
||||
})
|
||||
.catch(e => {
|
||||
this.$q.loading.hide();
|
||||
this.onOk();
|
||||
this.notifyError("There was an error editing the custom field");
|
||||
});
|
||||
} else {
|
||||
this.$axios
|
||||
.post("/core/customfields/", data)
|
||||
.then(r => {
|
||||
this.$q.loading.hide();
|
||||
this.onOk();
|
||||
this.notifySuccess("Custom field added!");
|
||||
})
|
||||
.catch(e => {
|
||||
this.$q.loading.hide();
|
||||
this.notifyError("There was an error adding the custom field");
|
||||
});
|
||||
}
|
||||
},
|
||||
clear() {
|
||||
this.localField.options = [];
|
||||
this.localField.default_value =
|
||||
this.localField.type === "single" || this.localField.type === "multiple" ? [] : "";
|
||||
this.localField.required = false;
|
||||
},
|
||||
show() {
|
||||
this.$refs.dialog.show();
|
||||
},
|
||||
hide() {
|
||||
this.$refs.dialog.hide();
|
||||
},
|
||||
onHide() {
|
||||
this.$emit("hide");
|
||||
},
|
||||
onOk() {
|
||||
this.$emit("ok");
|
||||
this.hide();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// If pk prop is set that means we are editting
|
||||
if (this.field) Object.assign(this.localField, this.field);
|
||||
|
||||
// Set model to current tab
|
||||
if (this.model) this.localField.model = this.model;
|
||||
},
|
||||
};
|
||||
</script>
|
||||
136
src/components/modals/coresettings/CustomFieldsTable.vue
Normal file
136
src/components/modals/coresettings/CustomFieldsTable.vue
Normal file
@@ -0,0 +1,136 @@
|
||||
<template>
|
||||
<q-table
|
||||
dense
|
||||
:data="data"
|
||||
:columns="columns"
|
||||
:pagination.sync="pagination"
|
||||
row-key="id"
|
||||
binary-state-sort
|
||||
hide-pagination
|
||||
virtual-scroll
|
||||
:rows-per-page-options="[0]"
|
||||
no-data-label="No Custom Fields"
|
||||
>
|
||||
<!-- body slots -->
|
||||
<template v-slot:body="props">
|
||||
<q-tr
|
||||
:props="props"
|
||||
class="cursor-pointer"
|
||||
@contextmenu="selectedTemplate = props.row"
|
||||
@dblclick="editCustomField(props.row)"
|
||||
>
|
||||
<!-- context menu -->
|
||||
<q-menu context-menu>
|
||||
<q-list dense style="min-width: 200px">
|
||||
<q-item clickable v-close-popup @click="editCustomField(props.row)">
|
||||
<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="deleteCustomField(props.row)">
|
||||
<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>
|
||||
<!-- name -->
|
||||
<q-td>
|
||||
{{ props.row.name }}
|
||||
</q-td>
|
||||
<!-- type -->
|
||||
<q-td>
|
||||
{{ props.row.type }}
|
||||
</q-td>
|
||||
<!-- default value -->
|
||||
<q-td>
|
||||
{{ props.row.default_value }}
|
||||
</q-td>
|
||||
<!-- required -->
|
||||
<q-td>
|
||||
<q-icon v-if="props.row.required" name="check" />
|
||||
</q-td>
|
||||
</q-tr>
|
||||
</template>
|
||||
</q-table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CustomFieldsForm from "@/components/modals/coresettings/CustomFieldsForm";
|
||||
import mixins from "@/mixins/mixins"
|
||||
|
||||
export default {
|
||||
name: "CustomFieldsTable",
|
||||
mixins: [mixins],
|
||||
props: {
|
||||
data: !Array,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pagination: {
|
||||
rowsPerPage: 0,
|
||||
sortBy: "name",
|
||||
descending: true,
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
name: "name",
|
||||
label: "Name",
|
||||
field: "name",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{ name: "type", label: "Field Type", field: "type", align: "left", sortable: true, format: (string => this.capitalize(string)) },
|
||||
{ name: "default_value", label: "Default Value", field: "default_value", align: "left", sortable: true },
|
||||
{ name: "required", label: "Required", field: "required", align: "left", sortable: true },
|
||||
],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
editCustomField(field) {
|
||||
this.$q
|
||||
.dialog({
|
||||
component: CustomFieldsForm,
|
||||
parent: this,
|
||||
field: field,
|
||||
})
|
||||
.onOk(() => {
|
||||
this.refresh();
|
||||
});
|
||||
},
|
||||
deleteCustomField(field) {
|
||||
this.$q
|
||||
.dialog({
|
||||
title: `Delete custom field ${field.name}?`,
|
||||
cancel: true,
|
||||
ok: { label: "Delete", color: "negative" },
|
||||
})
|
||||
.onOk(() => {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.delete(`core/customfields/${field.id}/`)
|
||||
.then(r => {
|
||||
this.refresh();
|
||||
this.$q.loading.hide();
|
||||
this.notifySuccess(`Custom Field ${field.name} was deleted!`);
|
||||
})
|
||||
.catch(error => {
|
||||
this.$q.loading.hide();
|
||||
this.notifyError(`An Error occured while deleting custom field: ${field.name}`);
|
||||
});
|
||||
});
|
||||
},
|
||||
refresh() {
|
||||
this.$emit("refresh");
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -7,6 +7,7 @@
|
||||
<q-tab name="emailalerts" label="Email Alerts" />
|
||||
<q-tab name="smsalerts" label="SMS Alerts" />
|
||||
<q-tab name="meshcentral" label="MeshCentral" />
|
||||
<q-tab name="customfields" label="Custom Fields" />
|
||||
</q-tabs>
|
||||
</template>
|
||||
<template v-slot:after>
|
||||
@@ -289,10 +290,13 @@
|
||||
<q-input dense filled v-model="settings.mesh_token" class="col-6" />
|
||||
</q-card-section>
|
||||
</q-tab-panel>
|
||||
<q-tab-panel name="customfields">
|
||||
<CustomFields />
|
||||
</q-tab-panel>
|
||||
</q-tab-panels>
|
||||
</q-scroll-area>
|
||||
<q-card-section class="row items-center">
|
||||
<q-btn label="Save" color="primary" type="submit" />
|
||||
<q-btn v-show="tab !== 'customfields'" label="Save" color="primary" type="submit" />
|
||||
<q-btn
|
||||
v-show="tab === 'emailalerts'"
|
||||
label="Save and Test"
|
||||
@@ -311,9 +315,13 @@
|
||||
<script>
|
||||
import mixins from "@/mixins/mixins";
|
||||
import ResetPatchPolicy from "@/components/modals/coresettings/ResetPatchPolicy";
|
||||
import CustomFields from "@/components/modals/coresettings/CustomFields";
|
||||
|
||||
export default {
|
||||
name: "EditCoreSettings",
|
||||
components: {
|
||||
CustomFields,
|
||||
},
|
||||
mixins: [mixins],
|
||||
data() {
|
||||
return {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Notify, date } from "quasar";
|
||||
import axios from 'axios'
|
||||
|
||||
export function notifySuccessConfig(msg, timeout = 2000) {
|
||||
return {
|
||||
@@ -139,6 +140,23 @@ export default {
|
||||
},
|
||||
capitalize(string) {
|
||||
return string[0].toUpperCase() + string.substring(1)
|
||||
}
|
||||
},
|
||||
getCustomFields(model) {
|
||||
return axios.patch("/core/customfields/", { model: model })
|
||||
.catch(e => {
|
||||
this.notifyError("There was an issue getting Custom Fields")
|
||||
})
|
||||
},
|
||||
formatCustomFields(fields, values) {
|
||||
let tempArray = []
|
||||
|
||||
for (let field of fields) {
|
||||
let obj = { value: values[field.name], field: field.id }
|
||||
tempArray.push(obj)
|
||||
|
||||
}
|
||||
return tempArray
|
||||
},
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -238,6 +238,7 @@ export default function () {
|
||||
raw: `Site|${site.id}`,
|
||||
header: "generic",
|
||||
icon: "apartment",
|
||||
client: client.id,
|
||||
server_policy: site.server_policy,
|
||||
workstation_policy: site.workstation_policy,
|
||||
alert_template: site.alert_template
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
</q-header>
|
||||
|
||||
<q-page-container>
|
||||
<FileBar :clients="clients" @edited="refreshEntireSite" />
|
||||
<FileBar />
|
||||
<q-splitter v-model="outsideModel">
|
||||
<template v-slot:before>
|
||||
<div v-if="!treeReady" class="q-pa-sm q-gutter-sm text-center" style="height: 30vh">
|
||||
@@ -119,13 +119,13 @@
|
||||
|
||||
<q-menu context-menu>
|
||||
<q-list dense style="min-width: 200px">
|
||||
<q-item clickable v-close-popup @click="showEditModal(props.node, 'edit')">
|
||||
<q-item clickable v-close-popup @click="showEditModal(props.node)">
|
||||
<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="showDeleteModal(props.node, 'delete')">
|
||||
<q-item clickable v-close-popup @click="showDeleteModal(props.node)">
|
||||
<q-item-section side>
|
||||
<q-icon name="delete" />
|
||||
</q-item-section>
|
||||
@@ -134,6 +134,18 @@
|
||||
|
||||
<q-separator></q-separator>
|
||||
|
||||
<q-item
|
||||
v-if="props.node.children"
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showAddSiteModal(props.node)"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="add" />
|
||||
</q-item-section>
|
||||
<q-item-section>Add Site</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-item clickable v-close-popup @click="showToggleMaintenance(props.node)">
|
||||
<q-item-section side>
|
||||
<q-icon name="construction" />
|
||||
@@ -338,24 +350,6 @@
|
||||
</q-splitter>
|
||||
</q-page-container>
|
||||
|
||||
<!-- client form modal -->
|
||||
<q-dialog v-model="showClientsFormModal" @hide="closeClientsFormModal">
|
||||
<ClientsForm
|
||||
@close="closeClientsFormModal"
|
||||
:op="clientOp"
|
||||
:clientpk="deleteEditModalPk"
|
||||
@edited="refreshEntireSite"
|
||||
/>
|
||||
</q-dialog>
|
||||
<!-- edit site modal -->
|
||||
<q-dialog v-model="showSitesFormModal" @hide="closeClientsFormModal">
|
||||
<SitesForm
|
||||
@close="closeClientsFormModal"
|
||||
:op="clientOp"
|
||||
:sitepk="deleteEditModalPk"
|
||||
@edited="refreshEntireSite"
|
||||
/>
|
||||
</q-dialog>
|
||||
<!-- install agent modal -->
|
||||
<q-dialog v-model="showInstallAgentModal" @hide="closeInstallAgent">
|
||||
<InstallAgent @close="closeInstallAgent" :sitepk="parseInt(sitePk)" />
|
||||
@@ -369,7 +363,6 @@
|
||||
|
||||
<script>
|
||||
import mixins from "@/mixins/mixins";
|
||||
import { notifySuccessConfig, notifyErrorConfig } from "@/mixins/mixins";
|
||||
import { mapState, mapGetters } from "vuex";
|
||||
import FileBar from "@/components/FileBar";
|
||||
import AgentTable from "@/components/AgentTable";
|
||||
@@ -378,6 +371,7 @@ import AlertsIcon from "@/components/AlertsIcon";
|
||||
import PolicyAdd from "@/components/automation/modals/PolicyAdd";
|
||||
import ClientsForm from "@/components/modals/clients/ClientsForm";
|
||||
import SitesForm from "@/components/modals/clients/SitesForm";
|
||||
import DeleteClient from "@/components/modals/clients/DeleteClient";
|
||||
import InstallAgent from "@/components/modals/agents/InstallAgent";
|
||||
import UserPreferences from "@/components/modals/coresettings/UserPreferences";
|
||||
import AlertTemplateAdd from "@/components/modals/alerts/AlertTemplateAdd";
|
||||
@@ -388,8 +382,6 @@ export default {
|
||||
AgentTable,
|
||||
SubTableTabs,
|
||||
AlertsIcon,
|
||||
ClientsForm,
|
||||
SitesForm,
|
||||
InstallAgent,
|
||||
UserPreferences,
|
||||
},
|
||||
@@ -397,12 +389,8 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
darkMode: true,
|
||||
showClientsFormModal: false,
|
||||
showSitesFormModal: false,
|
||||
deleteEditModalPk: null,
|
||||
showInstallAgentModal: false,
|
||||
sitePk: null,
|
||||
clientOp: null,
|
||||
serverCount: 0,
|
||||
serverOfflineCount: 0,
|
||||
workstationCount: 0,
|
||||
@@ -621,53 +609,45 @@ export default {
|
||||
});
|
||||
},
|
||||
showPolicyAdd(node) {
|
||||
if (node.children) {
|
||||
this.$q
|
||||
.dialog({
|
||||
component: PolicyAdd,
|
||||
parent: this,
|
||||
type: "client",
|
||||
object: node,
|
||||
})
|
||||
.onOk(() => {
|
||||
this.getTree();
|
||||
});
|
||||
} else {
|
||||
this.$q
|
||||
.dialog({
|
||||
component: PolicyAdd,
|
||||
parent: this,
|
||||
type: "site",
|
||||
object: node,
|
||||
})
|
||||
.onOk(() => {
|
||||
this.getTree();
|
||||
});
|
||||
}
|
||||
this.$q
|
||||
.dialog({
|
||||
component: PolicyAdd,
|
||||
parent: this,
|
||||
type: node.children ? "client" : "site",
|
||||
object: node,
|
||||
})
|
||||
.onOk(() => {
|
||||
this.getTree();
|
||||
});
|
||||
},
|
||||
showEditModal(node, op) {
|
||||
this.deleteEditModalPk = node.id;
|
||||
this.clientOp = op;
|
||||
if (node.children) {
|
||||
this.showClientsFormModal = true;
|
||||
} else {
|
||||
this.showSitesFormModal = true;
|
||||
}
|
||||
showAddSiteModal(node) {
|
||||
this.$q.dialog({
|
||||
component: SitesForm,
|
||||
parent: this,
|
||||
client: node.id,
|
||||
});
|
||||
},
|
||||
showDeleteModal(node, op) {
|
||||
this.deleteEditModalPk = node.id;
|
||||
this.clientOp = op;
|
||||
showEditModal(node) {
|
||||
let props = {};
|
||||
if (node.children) {
|
||||
this.showClientsFormModal = true;
|
||||
props.client = { id: node.id, name: node.label };
|
||||
} else {
|
||||
this.showSitesFormModal = true;
|
||||
props.site = { id: node.id, name: node.label, client: node.client };
|
||||
}
|
||||
|
||||
this.$q.dialog({
|
||||
component: node.children ? ClientsForm : SitesForm,
|
||||
parent: this,
|
||||
...props,
|
||||
});
|
||||
},
|
||||
closeClientsFormModal() {
|
||||
this.showClientsFormModal = false;
|
||||
this.showSitesFormModal = false;
|
||||
this.deleteEditModalPk = null;
|
||||
this.clientOp = null;
|
||||
showDeleteModal(node) {
|
||||
this.$q.dialog({
|
||||
component: DeleteClient,
|
||||
parent: this,
|
||||
object: { id: node.id, name: node.label },
|
||||
type: node.children ? "client" : "site",
|
||||
});
|
||||
},
|
||||
showInstallAgent(node) {
|
||||
this.sitePk = node.id;
|
||||
@@ -734,11 +714,11 @@ export default {
|
||||
this.$store
|
||||
.dispatch("toggleMaintenanceMode", data)
|
||||
.then(response => {
|
||||
this.$q.notify(notifySuccessConfig(text));
|
||||
this.notifySuccess(text);
|
||||
this.getTree();
|
||||
})
|
||||
.catch(error => {
|
||||
this.$q.notify(notifyErrorConfig("An Error occured. Please try again"));
|
||||
this.notifyError("An Error occured. Please try again");
|
||||
});
|
||||
},
|
||||
menuMaintenanceText(node) {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<q-form @submit.prevent="finish">
|
||||
<q-card-section>
|
||||
<div>Add Client:</div>
|
||||
<q-input dense outlined v-model="client.client" :rules="[val => !!val || '*Required']">
|
||||
<q-input dense outlined v-model="client.name" :rules="[val => !!val || '*Required']">
|
||||
<template v-slot:prepend>
|
||||
<q-icon name="business" />
|
||||
</template>
|
||||
@@ -18,7 +18,7 @@
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<div>Add Site:</div>
|
||||
<q-input dense outlined v-model="client.site" :rules="[val => !!val || '*Required']">
|
||||
<q-input dense outlined v-model="site.name" :rules="[val => !!val || '*Required']">
|
||||
<template v-slot:prepend>
|
||||
<q-icon name="apartment" />
|
||||
</template>
|
||||
@@ -66,8 +66,10 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
client: {
|
||||
client: null,
|
||||
site: null,
|
||||
name: "",
|
||||
},
|
||||
site: {
|
||||
name: "",
|
||||
},
|
||||
meshagent: null,
|
||||
allTimezones: [],
|
||||
@@ -80,6 +82,7 @@ export default {
|
||||
this.$q.loading.show();
|
||||
const data = {
|
||||
client: this.client,
|
||||
site: this.site,
|
||||
timezone: this.timezone,
|
||||
initialsetup: true,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user