auto format everything

This commit is contained in:
wh1te909
2020-05-14 06:34:27 +00:00
parent 985947f30e
commit 3af4071219
66 changed files with 622 additions and 858 deletions

4
.gitignore vendored
View File

@@ -28,4 +28,6 @@ meshagent.exe
app.ini
.env.dev
.env
*.pem
*.pem
create_services.py
gen_random.py

View File

@@ -4,6 +4,7 @@ import os
PROGRAM_DIR = "C:\\Program Files\\TacticalAgent"
def get_services():
return [svc.as_dict() for svc in psutil.win_service_iter()]
@@ -30,6 +31,7 @@ def update_salt():
__salt__["cmd.run_bg"]([tacrmm, "-m", "updatesalt"])
return "ok"
def run_manual_checks():
tacrmm = os.path.join(PROGRAM_DIR, "tacticalrmm.exe")
__salt__["cmd.run_bg"]([tacrmm, "-m", "runchecks"])

View File

@@ -6,4 +6,3 @@ from .models import User
admin.site.register(User)
TokenAdmin.raw_id_fields = ("user",)

View File

@@ -266,32 +266,3 @@ class Agent(models.Model):
versions[i] = release["name"]
return {"versions": versions, "data": r.json()}
""" @staticmethod
def salt_cmd(tgt, fun, arg=[], timeout=60, kwargs={}):
return local.cmd(
tgt,
fun,
arg,
timeout=timeout,
tgt_type="glob",
ret="",
jid="",
full_return=False,
kwarg=kwargs,
username=settings.SALT_USERNAME,
password=settings.SALT_PASSWORD,
eauth="pam"
)
@staticmethod
def salt_wheel_cmd(hostname, func):
resp = wheel.cmd_sync({
"fun": func,
"match": hostname,
"username": settings.SALT_USERNAME,
"password": settings.SALT_PASSWORD,
"eauth": "pam"
}, timeout=100)
return resp """

View File

@@ -98,7 +98,7 @@ class TestAgentViews(BaseTestCase):
# TODO
# decode the cookie
self.assertIn("&hide=31", r.data)
self.assertIn("&viewmode=11", r.data)
self.assertIsInstance(r.data, str)

View File

@@ -2,4 +2,4 @@ from django.apps import AppConfig
class AutomationConfig(AppConfig):
name = 'automation'
name = "automation"

View File

@@ -37,6 +37,7 @@ TASK_TYPE_CHOICES = [
("manual", "Manual"),
]
class AutomatedTask(models.Model):
agent = models.ForeignKey(Agent, related_name="autotasks", on_delete=models.CASCADE)
name = models.CharField(max_length=255)
@@ -89,7 +90,9 @@ class AutomatedTask(models.Model):
if i in j:
ret.append(j[1][0:3])
run_time_nice = dt.datetime.strptime(self.run_time_minute, "%H:%M").strftime("%I:%M %p")
run_time_nice = dt.datetime.strptime(
self.run_time_minute, "%H:%M"
).strftime("%I:%M %p")
if len(ret) == 7:
return f"Every day at {run_time_nice}"
@@ -133,7 +136,7 @@ class AutomatedTask(models.Model):
def generate_task_name():
chars = string.ascii_letters
return "TacticalRMM_" + "".join(random.choice(chars) for i in range(35))
@staticmethod
def get_related_check(data):
from checks.models import (

View File

@@ -4,14 +4,14 @@ from .models import Policy, AutomatedTask
from agents.models import Agent
from checks.serializers import ScriptSerializer
class PolicySerializer(serializers.ModelSerializer):
class PolicySerializer(serializers.ModelSerializer):
class Meta:
model = Policy
fields = "__all__"
class PolicyRelationSerializer(serializers.ModelSerializer):
class Meta:
model = Policy
fields = "__all__"
@@ -28,13 +28,18 @@ class TaskSerializer(serializers.ModelSerializer):
fields = "__all__"
depth = 1
class AgentTaskSerializer(serializers.ModelSerializer):
script = ScriptSerializer(read_only=True)
class Meta:
model = AutomatedTask
fields = ("timeout", "script",)
fields = (
"timeout",
"script",
)
class AutoTaskSerializer(serializers.ModelSerializer):
@@ -48,6 +53,7 @@ class AutoTaskSerializer(serializers.ModelSerializer):
"autotasks",
)
class AutoTaskPolicySerializer(serializers.ModelSerializer):
autotasks = TaskSerializer(many=True, read_only=True)

View File

@@ -17,11 +17,11 @@ from checks.models import Script
from clients.models import Client, Site
from .serializers import (
PolicySerializer,
PolicySerializer,
PolicyRelationSerializer,
AutoTaskPolicySerializer,
AutoTaskSerializer,
AgentTaskSerializer
AutoTaskSerializer,
AgentTaskSerializer,
)
from checks.serializers import ScriptSerializer
@@ -32,6 +32,7 @@ from .tasks import (
enable_or_disable_win_task,
)
class GetAddPolicies(APIView):
def get(self, request):
@@ -53,20 +54,21 @@ class GetAddPolicies(APIView):
except DataError:
content = {"error": "Policy name too long (max 255 chars)"}
return Response(content, status=status.HTTP_400_BAD_REQUEST)
# Add Clients, Sites, and Agents to Policy
if (len(request.data["clients"]) > 0):
if len(request.data["clients"]) > 0:
policy.clients.set(request.data["clients"])
if (len(request.data["sites"]) > 0):
if len(request.data["sites"]) > 0:
policy.sites.set(request.data["sites"])
if (len(request.data["agents"]) > 0):
if len(request.data["agents"]) > 0:
policy.agents.set(request.data["agents"])
return Response("ok")
class GetUpdateDeletePolicy(APIView):
class GetUpdateDeletePolicy(APIView):
def get(self, request, pk):
policy = get_object_or_404(Policy, pk=pk)
@@ -88,21 +90,21 @@ class GetUpdateDeletePolicy(APIView):
return Response(content, status=status.HTTP_400_BAD_REQUEST)
# Update Clients, Sites, and Agents to Policy
if (len(request.data["clients"]) > 0):
if len(request.data["clients"]) > 0:
policy.clients.set(request.data["clients"])
else:
policy.clients.clear()
if (len(request.data["sites"]) > 0):
if len(request.data["sites"]) > 0:
policy.sites.set(request.data["sites"])
else:
policy.sites.clear()
if (len(request.data["agents"]) > 0):
if len(request.data["agents"]) > 0:
policy.agents.set(request.data["agents"])
else:
policy.agents.clear()
return Response("ok")
def delete(self, request, pk):
@@ -196,6 +198,7 @@ class PolicyAutoTask(APIView):
policy = Policy.objects.only("pk").get(pk=pk)
return Response(AutoTaskPolicySerializer(policy).data)
@api_view()
def run_task(request, pk):
task = get_object_or_404(AutomatedTask, pk=pk)
@@ -226,8 +229,7 @@ class TaskRunner(APIView):
return Response("ok")
class OverviewPolicy(APIView):
class OverviewPolicy(APIView):
def get(self, request):
clients = Client.objects.all()
@@ -244,14 +246,15 @@ class OverviewPolicy(APIView):
sites = Site.objects.filter(client=client)
for site in sites:
client_sites["sites"][site.site] = {}
policies = Policy.objects.filter(sites__id=site.id)
client_sites["sites"][site.site]["policies"] = list(PolicySerializer(policies, many=True).data)
client_sites["sites"][site.site]["policies"] = list(
PolicySerializer(policies, many=True).data
)
response[client.client] = client_sites
return Response(response)

View File

@@ -5,10 +5,7 @@ from .models import Client, Site
class ClientSerializer(serializers.ModelSerializer):
class Meta:
model = Client
fields = (
"id",
"client"
)
fields = ("id", "client")
class SiteSerializer(serializers.ModelSerializer):
@@ -27,4 +24,3 @@ class TreeSerializer(serializers.ModelSerializer):
"site",
"client_name",
)

View File

@@ -1,3 +1 @@
from django.test import TestCase

View File

@@ -11,4 +11,3 @@ class ServicesSerializer(serializers.ModelSerializer):
"pk",
"services",
)

View File

@@ -19,7 +19,7 @@ class ChocoSoftware(models.Model):
]
biggest = max(range(len(sizes)), key=lambda index: sizes[index]["size"])
return int(sizes[biggest]["pk"])
@classmethod
def combine_all(cls):
from .serializers import ChocoSoftwareSerializer
@@ -28,17 +28,16 @@ class ChocoSoftware(models.Model):
combined = []
for i in chocos:
combined.extend(ChocoSoftwareSerializer(i).data["chocos"])
# remove duplicates
return [dict(t) for t in {tuple(d.items()) for d in combined}]
def __str__(self):
from .serializers import ChocoSoftwareSerializer
return str(len(ChocoSoftwareSerializer(self).data["chocos"])) + f" - {self.added}"
return (
str(len(ChocoSoftwareSerializer(self).data["chocos"])) + f" - {self.added}"
)
class ChocoLog(models.Model):

View File

@@ -62,7 +62,7 @@ def update_chocos():
continue
else:
if data:
resp = agent.salt_api_cmd(
hostname=agent.salt_id, timeout=200, func="chocolatey.list"
)

View File

@@ -2,4 +2,4 @@ from __future__ import absolute_import, unicode_literals
from .celery import app as celery_app
__all__ = ('celery_app',)
__all__ = ("celery_app",)

View File

@@ -11,6 +11,6 @@ import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'tacticalrmm.settings')
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tacticalrmm.settings")
application = get_wsgi_application()

View File

@@ -74,7 +74,9 @@ class WinUpdatePolicy(models.Model):
run_time_hour = models.IntegerField(choices=RUN_TIME_HOUR_CHOICES, default=3)
# 0 to 6 = Monday to Sunday
run_time_days = ArrayField(models.IntegerField(blank=True), null=True, blank=True, default=list)
run_time_days = ArrayField(
models.IntegerField(blank=True), null=True, blank=True, default=list
)
reboot_after_install = models.CharField(
max_length=50, choices=REBOOT_AFTER_INSTALL_CHOICES, default="required"
@@ -86,4 +88,3 @@ class WinUpdatePolicy(models.Model):
def __str__(self):
return self.agent.hostname

View File

@@ -47,4 +47,3 @@ class ApprovedUpdateSerializer(serializers.ModelSerializer):
"winupdates",
"patch_policy",
)

View File

@@ -7,7 +7,7 @@ from tacticalrmm.celery import app
@app.task
def check_for_updates_task(pk, wait=False):
if wait:
sleep(70)

View File

@@ -1,48 +1,44 @@
<template>
<q-btn dense flat icon="notifications">
<q-badge color="red" floating transparent>
{{ test_alerts.length }}
</q-badge>
<q-badge color="red" floating transparent>{{ test_alerts.length }}</q-badge>
<q-menu>
<q-list separator>
<q-item v-for="alert in test_alerts" :key="alert.id">
<q-item-section>
<q-item-label>{{ alert.client }} - {{ alert.hostname }}</q-item-label>
<q-item-label caption>
<q-icon :class="`text-${alertColor(alert.type)}`" :name="alert.type"></q-icon>
{{ alert.message }}</q-item-label>
<q-icon :class="`text-${alertColor(alert.type)}`" :name="alert.type"></q-icon>
{{ alert.message }}
</q-item-label>
</q-item-section>
<q-item-section side top>
<q-item-label caption>{{ alert.timestamp }}</q-item-label>
</q-item-section>
</q-item>
<q-item clickable @click="showAlertsModal = true">
View All Alerts ({{test_alerts.length}})
</q-item>
<q-item clickable @click="showAlertsModal = true">View All Alerts ({{test_alerts.length}})</q-item>
</q-list>
</q-menu>
<q-dialog
v-model="showAlertsModal"
maximized
transition-show="slide-up"
transition-hide="slide-down"
>
<AlertsOverview @close="showAlertsModal = false" />
</q-dialog>
<q-dialog
v-model="showAlertsModal"
maximized
transition-show="slide-up"
transition-hide="slide-down"
>
<AlertsOverview @close="showAlertsModal = false" />
</q-dialog>
</q-btn>
</template>
<script>
import { mapState } from 'vuex';
import AlertsOverview from '@/components/modals/alerts/AlertsOverview'
import { mapState } from "vuex";
import AlertsOverview from "@/components/modals/alerts/AlertsOverview";
export default {
name: "AlertsIcon",
components: {AlertsOverview},
data () {
components: { AlertsOverview },
data() {
return {
showAlertsModal: false,
test_alerts: [
@@ -65,22 +61,22 @@ export default {
timestamp: "5 hours ago"
}
]
}
};
},
methods: {
alertColor (type) {
if (type === "error"){
alertColor(type) {
if (type === "error") {
return "red";
}
if (type === "warning"){
return "orange"
}
if (type === "warning") {
return "orange";
}
}
},
computed: {
...mapState('alerts/', {
...mapState("alerts/", {
alerts: state => state.alerts
})
}
}
};
</script>

View File

@@ -3,7 +3,14 @@
<div v-else-if="Object.keys(automatedTasks).length === 0">No Tasks</div>
<div class="row" v-else>
<div class="col-12">
<q-btn size="sm" color="grey-5" icon="fas fa-plus" label="Add Task" text-color="black" @click="showAddAutomatedTask = true" />
<q-btn
size="sm"
color="grey-5"
icon="fas fa-plus"
label="Add Task"
text-color="black"
@click="showAddAutomatedTask = true"
/>
<q-btn dense flat push @click="refreshTasks(automatedTasks.pk)" icon="refresh" />
<template v-if="tasks === undefined || tasks.length === 0">
<p>No Tasks</p>
@@ -184,10 +191,7 @@ export default {
axios
.delete(`/automation/${pk}/automatedtasks/`)
.then(r => {
this.$store.dispatch(
"loadAutomatedTasks",
this.automatedTasks.pk
);
this.$store.dispatch("loadAutomatedTasks", this.automatedTasks.pk);
this.$store.dispatch("loadChecks", this.automatedTasks.pk);
this.notifySuccess(r.data);
})

View File

@@ -313,7 +313,7 @@ export default {
field: "last_run",
align: "left"
},
{ name: "assignedtasks", label: "Assigned Tasks", field: "assigned_task", align: "left" },
{ name: "assignedtasks", label: "Assigned Tasks", field: "assigned_task", align: "left" }
],
pagination: {
rowsPerPage: 9999

View File

@@ -161,15 +161,11 @@ export default {
},
startPoll() {
this.poll = true;
axios
.get(`/agents/${this.pk}/getprocs/`)
.then(r => (this.procs = r.data));
axios.get(`/agents/${this.pk}/getprocs/`).then(r => (this.procs = r.data));
this.refreshProcs();
},
getAgent() {
axios
.get(`/agents/${this.pk}/agentdetail/`)
.then(r => (this.mem = r.data.total_ram));
axios.get(`/agents/${this.pk}/agentdetail/`).then(r => (this.mem = r.data.total_ram));
},
convert(percent) {
const mb = this.mem * 1024;

View File

@@ -207,15 +207,16 @@ export default {
});
},
downloadScript() {
axios.get(`/checks/downloadscript/${this.selectedRow}/`, { responseType: 'blob' })
axios
.get(`/checks/downloadscript/${this.selectedRow}/`, { responseType: "blob" })
.then(({ data }) => {
const blob = new Blob([data], { type: 'text/plain' })
let link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = this.filename
link.click()
const blob = new Blob([data], { type: "text/plain" });
let link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.download = this.filename;
link.click();
})
.catch(error => console.error(error))
.catch(error => console.error(error));
}
},
computed: {

View File

@@ -12,37 +12,18 @@
hide-bottom
>
<template v-slot:top>
<q-btn
dense
flat
push
@click="refreshServices"
icon="refresh"
/>
<q-btn dense flat push @click="refreshServices" icon="refresh" />
<q-space />
<q-input
v-model="filter"
outlined
label="Search"
dense
clearable
>
<q-input v-model="filter" outlined label="Search" dense clearable>
<template v-slot:prepend>
<q-icon name="search" />
</template>
</q-input>
</template>
<template
slot="body"
slot-scope="props"
:props="props"
>
<template slot="body" slot-scope="props" :props="props">
<q-tr :props="props">
<q-menu context-menu>
<q-list
dense
style="min-width: 200px"
>
<q-list dense style="min-width: 200px">
<q-item
clickable
v-close-popup
@@ -65,38 +46,19 @@
<q-item-section>Restart</q-item-section>
</q-item>
<q-separator />
<q-item
clickable
v-close-popup
@click="editService(props.row.name)"
>
<q-item clickable v-close-popup @click="editService(props.row.name)">
<q-item-section>Service Details</q-item-section>
</q-item>
</q-list>
</q-menu>
<q-td
key="display_name"
:props="props"
>
<q-td key="display_name" :props="props">
<q-icon name="fas fa-cogs" />
&nbsp;&nbsp;&nbsp;{{ props.row.display_name }}
</q-td>
<q-td
key="start_type"
:props="props"
>{{ props.row.start_type }}</q-td>
<q-td
key="pid"
:props="props"
>{{ props.row.pid }}</q-td>
<q-td
key="status"
:props="props"
>{{ props.row.status }}</q-td>
<q-td
key="username"
:props="props"
>{{ props.row.username }}</q-td>
<q-td key="start_type" :props="props">{{ props.row.start_type }}</q-td>
<q-td key="pid" :props="props">{{ props.row.pid }}</q-td>
<q-td key="status" :props="props">{{ props.row.status }}</q-td>
<q-td key="username" :props="props">{{ props.row.username }}</q-td>
</q-tr>
</template>
</q-table>
@@ -121,10 +83,7 @@
<div class="row">
<div class="col-3">Description:</div>
<div class="col-9">
<q-field
outlined
color="black"
>{{ serviceData.Description }}</q-field>
<q-field outlined color="black">{{ serviceData.Description }}</q-field>
</div>
</div>
<br />
@@ -186,10 +145,7 @@
</div>
</q-card-section>
<hr />
<q-card-actions
align="left"
class="bg-white text-teal"
>
<q-card-actions align="left" class="bg-white text-teal">
<q-btn
:disable="saveServiceDetailButton"
dense
@@ -197,12 +153,7 @@
color="positive"
@click="changeStartupType(startupType, serviceData.svc_name)"
/>
<q-btn
dense
label="Cancel"
color="grey"
v-close-popup
/>
<q-btn dense label="Cancel" color="grey" v-close-popup />
</q-card-actions>
<q-inner-loading :showing="serviceDetailVisible" />
</q-card>
@@ -218,7 +169,7 @@ export default {
name: "Services",
props: ["pk"],
mixins: [mixins],
data () {
data() {
return {
servicesData: [],
serviceDetailsModal: false,
@@ -226,12 +177,7 @@ export default {
saveServiceDetailButton: true,
serviceData: {},
startupType: "",
startupOptions: [
"Automatic (Delayed Start)",
"Automatic",
"Manual",
"Disabled"
],
startupOptions: ["Automatic (Delayed Start)", "Automatic", "Manual", "Disabled"],
filter: "",
pagination: {
rowsPerPage: 9999,
@@ -278,7 +224,7 @@ export default {
};
},
methods: {
changeStartupType (startuptype, name) {
changeStartupType(startuptype, name) {
let changed;
switch (startuptype) {
case "Automatic (Delayed Start)":
@@ -315,10 +261,10 @@ export default {
this.notifyError(err.response.data.error);
});
},
startupTypeChanged () {
startupTypeChanged() {
this.saveServiceDetailButton = false;
},
editService (name) {
editService(name) {
this.saveServiceDetailButton = true;
this.serviceDetailsModal = true;
this.serviceDetailVisible = true;
@@ -328,15 +274,9 @@ export default {
this.serviceData = r.data;
this.serviceData.svc_name = name;
this.startupType = this.serviceData.StartType;
if (
this.serviceData.StartType === "Auto" &&
this.serviceData.StartTypeDelayed === true
) {
if (this.serviceData.StartType === "Auto" && this.serviceData.StartTypeDelayed === true) {
this.startupType = "Automatic (Delayed Start)";
} else if (
this.serviceData.StartType === "Auto" &&
this.serviceData.StartTypeDelayed === false
) {
} else if (this.serviceData.StartType === "Auto" && this.serviceData.StartTypeDelayed === false) {
this.startupType = "Automatic";
}
this.serviceDetailVisible = false;
@@ -347,7 +287,7 @@ export default {
this.notifyError(err.response.data.error);
});
},
serviceAction (name, action, fullname) {
serviceAction(name, action, fullname) {
let msg, status;
switch (action) {
case "start":
@@ -383,15 +323,15 @@ export default {
this.notifyError(err.response.data.error);
});
},
async getServices () {
async getServices() {
try {
let r = await axios.get(`/services/${this.pk}/services/`);
this.servicesData = [r.data][0].services;
} catch (e) {
console.log(`ERROR!: ${e}`)
console.log(`ERROR!: ${e}`);
}
},
refreshServices () {
refreshServices() {
this.$q.loading.show({ message: "Reloading services..." });
axios
.get(`/services/${this.pk}/refreshedservices/`)
@@ -405,7 +345,7 @@ export default {
});
}
},
created () {
created() {
this.getServices();
}
};

View File

@@ -1,62 +1,62 @@
<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="summary" icon="fas fa-info-circle" size="xs" label="Summary" />
<q-tab name="checks" icon="fas fa-check-double" label="Checks" />
<q-tab name="tasks" icon="fas fa-tasks" label="Tasks" />
<q-tab name="patches" icon="system_update" label="Patches" />
<q-tab name="software" icon="fab fa-windows" label="Software" />
</q-tabs>
<q-separator />
<q-tab-panels v-model="subtab" :animated="false">
<q-tab-panel name="summary">
<SummaryTab />
</q-tab-panel>
<q-tab-panel name="checks">
<ChecksTab />
</q-tab-panel>
<q-tab-panel name="tasks">
<AutomatedTasksTab />
</q-tab-panel>
<q-tab-panel name="patches">
<WindowsUpdates />
</q-tab-panel>
<q-tab-panel name="software">
<SoftwareTab />
</q-tab-panel>
</q-tab-panels>
</div>
<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="summary" icon="fas fa-info-circle" size="xs" label="Summary" />
<q-tab name="checks" icon="fas fa-check-double" label="Checks" />
<q-tab name="tasks" icon="fas fa-tasks" label="Tasks" />
<q-tab name="patches" icon="system_update" label="Patches" />
<q-tab name="software" icon="fab fa-windows" label="Software" />
</q-tabs>
<q-separator />
<q-tab-panels v-model="subtab" :animated="false">
<q-tab-panel name="summary">
<SummaryTab />
</q-tab-panel>
<q-tab-panel name="checks">
<ChecksTab />
</q-tab-panel>
<q-tab-panel name="tasks">
<AutomatedTasksTab />
</q-tab-panel>
<q-tab-panel name="patches">
<WindowsUpdates />
</q-tab-panel>
<q-tab-panel name="software">
<SoftwareTab />
</q-tab-panel>
</q-tab-panels>
</div>
</template>
<script>
import SummaryTab from '@/components/SummaryTab';
import ChecksTab from '@/components/ChecksTab';
import AutomatedTasksTab from '@/components/AutomatedTasksTab';
import WindowsUpdates from '@/components/WindowsUpdates';
import SoftwareTab from '@/components/SoftwareTab';
import SummaryTab from "@/components/SummaryTab";
import ChecksTab from "@/components/ChecksTab";
import AutomatedTasksTab from "@/components/AutomatedTasksTab";
import WindowsUpdates from "@/components/WindowsUpdates";
import SoftwareTab from "@/components/SoftwareTab";
export default {
name: "SubTableTabs",
components: {
SummaryTab,
ChecksTab,
AutomatedTasksTab,
WindowsUpdates,
SoftwareTab,
SummaryTab,
ChecksTab,
AutomatedTasksTab,
WindowsUpdates,
SoftwareTab
},
data() {
return {
subtab: 'summary'
}
return {
subtab: "summary"
};
}
};
</script>

View File

@@ -30,10 +30,7 @@
</q-item>
<!-- physical disks -->
<q-item
v-for="disk in summary.physical_disks"
:key="disk.model"
>
<q-item v-for="disk in summary.physical_disks" :key="disk.model">
<q-item-section avatar>
<q-icon name="far fa-hdd" />
</q-item-section>
@@ -57,10 +54,7 @@
<!-- right -->
<div class="col-3">
<span class="text-subtitle2 text-bold">Disks</span>
<div
v-for="disk in disks"
:key="disk.device"
>
<div v-for="disk in disks" :key="disk.device">
<span>{{ disk.device }} ({{ disk.fstype }})</span>
<q-linear-progress
rounded
@@ -80,16 +74,15 @@
<script>
export default {
name: "SummaryTab",
data () {
data() {
return {};
},
methods: {
},
methods: {},
computed: {
summary () {
summary() {
return this.$store.state.agentSummary;
},
disks () {
disks() {
const entries = Object.entries(this.summary.disks);
const ret = [];
for (let [k, v] of entries) {

View File

@@ -1,6 +1,8 @@
<template>
<div v-if="!selectedAgentPk">No agent selected</div>
<div v-else-if="managedByWsus">Patch management is not available for this agent because it is managed by WSUS</div>
<div
v-else-if="managedByWsus"
>Patch management is not available for this agent because it is managed by WSUS</div>
<div v-else-if="Object.keys(sortedUpdates).length === 0">No Patches</div>
<div v-else class="q-pa-xs">
<q-btn label="Refresh" dense flat push @click="refreshUpdates(updates.pk)" icon="refresh" />
@@ -22,16 +24,36 @@
<q-tr :props="props">
<q-menu context-menu>
<q-list dense style="min-width: 100px">
<q-item v-if="!props.row.installed" clickable v-close-popup @click="editPolicy(props.row.id, 'inherit')">
<q-item
v-if="!props.row.installed"
clickable
v-close-popup
@click="editPolicy(props.row.id, 'inherit')"
>
<q-item-section>Inherit</q-item-section>
</q-item>
<q-item v-if="!props.row.installed" clickable v-close-popup @click="editPolicy(props.row.id, 'approve')">
<q-item
v-if="!props.row.installed"
clickable
v-close-popup
@click="editPolicy(props.row.id, 'approve')"
>
<q-item-section>Approve</q-item-section>
</q-item>
<q-item v-if="!props.row.installed" clickable v-close-popup @click="editPolicy(props.row.id, 'ignore')">
<q-item
v-if="!props.row.installed"
clickable
v-close-popup
@click="editPolicy(props.row.id, 'ignore')"
>
<q-item-section>Ignore</q-item-section>
</q-item>
<q-item v-if="!props.row.installed" clickable v-close-popup @click="editPolicy(props.row.id, 'nothing')">
<q-item
v-if="!props.row.installed"
clickable
v-close-popup
@click="editPolicy(props.row.id, 'nothing')"
>
<q-item-section>Do Nothing</q-item-section>
</q-item>
</q-list>
@@ -47,15 +69,27 @@
<q-icon v-else-if="props.row.action === 'ignore'" name="fas fa-check" color="negative">
<q-tooltip>Ignore</q-tooltip>
</q-icon>
<q-icon v-else-if="props.row.action === 'inherit'" name="fiber_manual_record" color="accent">
<q-icon
v-else-if="props.row.action === 'inherit'"
name="fiber_manual_record"
color="accent"
>
<q-tooltip>Inherit</q-tooltip>
</q-icon>
</q-td>
<q-td>
<q-icon v-if="props.row.installed" name="fas fa-check" color="positive"><q-tooltip>Installed</q-tooltip></q-icon>
<q-icon v-else-if="props.row.action == 'approve'" name="fas fa-tasks" color="primary"><q-tooltip>Pending</q-tooltip></q-icon>
<q-icon v-else-if="props.row.action == 'ignore'" name="fas fa-ban" color="negative"><q-tooltip>Ignored</q-tooltip></q-icon>
<q-icon v-else name="fas fa-exclamation" color="warning"><q-tooltip>Missing</q-tooltip></q-icon>
<q-icon v-if="props.row.installed" name="fas fa-check" color="positive">
<q-tooltip>Installed</q-tooltip>
</q-icon>
<q-icon v-else-if="props.row.action == 'approve'" name="fas fa-tasks" color="primary">
<q-tooltip>Pending</q-tooltip>
</q-icon>
<q-icon v-else-if="props.row.action == 'ignore'" name="fas fa-ban" color="negative">
<q-tooltip>Ignored</q-tooltip>
</q-icon>
<q-icon v-else name="fas fa-exclamation" color="warning">
<q-tooltip>Missing</q-tooltip>
</q-icon>
</q-td>
<q-td>{{ props.row.severity }}</q-td>
<q-td>{{ formatMessage(props.row.title) }}</q-td>
@@ -129,14 +163,7 @@ export default {
sortable: true
}
],
visibleColumns: [
"action",
"installed",
"severity",
"title",
"description",
"date_installed",
]
visibleColumns: ["action", "installed", "severity", "title", "description", "date_installed"]
};
},
methods: {

View File

@@ -2,7 +2,15 @@
<div style="width: 900px; max-width: 90vw;">
<q-card>
<q-bar>
<q-btn ref="refresh" @click="getPolicies; clearRow()" class="q-mr-sm" dense flat push icon="refresh" />Automation Manager
<q-btn
ref="refresh"
@click="getPolicies; clearRow()"
class="q-mr-sm"
dense
flat
push
icon="refresh"
/>Automation Manager
<q-space />
<q-btn dense flat icon="close" v-close-popup>
<q-tooltip content-class="bg-white text-primary">Close</q-tooltip>
@@ -74,17 +82,11 @@
>
<template v-slot:header="props">
<q-tr :props="props">
<q-th v-for="col in props.cols" :key="col.name" :props="props">
{{ col.label }}
</q-th>
<q-th v-for="col in props.cols" :key="col.name" :props="props">{{ col.label }}</q-th>
</q-tr>
</template>
<template v-slot:body="props">
<q-tr
:props="props"
class="cursor-pointer"
@click="props.selected = true"
>
<q-tr :props="props" class="cursor-pointer" @click="props.selected = true">
<q-td>{{ props.row.name }}</q-td>
<q-td>{{ props.row.desc }}</q-td>
<q-td>{{ props.row.active }}</q-td>
@@ -111,16 +113,16 @@
<script>
import mixins from "@/mixins/mixins";
import { mapState } from 'vuex';
import { mapState } from "vuex";
import PolicyForm from "@/components/automation/modals/PolicyForm";
import PolicyOverview from "@/components/automation/PolicyOverview";
import PolicySubTableTabs from "@/components/automation/PolicySubTableTabs"
import PolicySubTableTabs from "@/components/automation/PolicySubTableTabs";
export default {
name: "AutomationManager",
components: { PolicyForm, PolicyOverview, PolicySubTableTabs },
mixins: [mixins],
data () {
data() {
return {
showPolicyFormModal: false,
showPolicyOverviewModal: false,
@@ -179,30 +181,30 @@ export default {
};
},
methods: {
getPolicies () {
this.$store.dispatch('automation/loadPolicies');
getPolicies() {
this.$store.dispatch("automation/loadPolicies");
},
policyRowSelected ({added, keys, rows}) {
policyRowSelected({ added, keys, rows }) {
// First key of the array is the selected row pk
this.$store.commit('automation/setSelectedPolicy', keys[0]);
this.$store.dispatch('automation/loadPolicyChecks', keys[0]);
this.$store.dispatch('automation/loadPolicyAutomatedTasks', keys[0]);
this.$store.commit("automation/setSelectedPolicy", keys[0]);
this.$store.dispatch("automation/loadPolicyChecks", keys[0]);
this.$store.dispatch("automation/loadPolicyAutomatedTasks", keys[0]);
},
clearRow () {
this.$store.commit('automation/setSelectedPolicy', null);
this.$store.commit('automation/setPolicyChecks', {});
this.$store.commit('automation/setPolicyAutomatedTasks', {});
clearRow() {
this.$store.commit("automation/setSelectedPolicy", null);
this.$store.commit("automation/setPolicyChecks", {});
this.$store.commit("automation/setPolicyAutomatedTasks", {});
},
deletePolicy () {
this.$q.dialog({
deletePolicy() {
this.$q
.dialog({
title: "Delete policy?",
cancel: true,
ok: { label: "Delete", color: "negative" }
})
.onOk(() => {
this.$store.dispatch('automation/deletePolicy', this.selectedRow)
this.$store
.dispatch("automation/deletePolicy", this.selectedRow)
.then(response => {
this.notifySuccess(`Policy was deleted!`);
})
@@ -210,15 +212,15 @@ export default {
this.notifyError(`An Error occured while deleting policy`);
});
});
},
}
},
computed: {
...mapState({
policies: state => state.automation.policies,
selectedRow: state => state.automation.selectedPolicy
}),
})
},
mounted () {
mounted() {
this.getPolicies();
}
};

View File

@@ -26,17 +26,11 @@
<q-tr>
<!-- tds -->
<q-td>
<q-checkbox
disabled
dense
v-model="props.row.enabled"
/>
<q-checkbox disabled dense v-model="props.row.enabled" />
</q-td>
<q-td>{{ props.row.name }}</q-td>
<q-td v-if="props.row.retcode || props.row.stdout || props.row.stderr">
<span
style="cursor:pointer;color:blue;text-decoration:underline"
>output</span>
<span style="cursor:pointer;color:blue;text-decoration:underline">output</span>
</q-td>
<q-td v-else>Awaiting output</q-td>
<q-td v-if="props.row.last_run">{{ props.row.last_run }}</q-td>
@@ -59,7 +53,7 @@ export default {
name: "OverviewAutomatedTasksTab",
props: ["policypk"],
mixins: [mixins],
data () {
data() {
return {
automatedTasks: {},
columns: [
@@ -95,27 +89,29 @@ export default {
}
};
},
mounted () {
mounted() {
this.getPolicyTasks();
},
watch: {
'policypk': function () {
policypk: function() {
this.getPolicyTasks();
}
},
methods: {
getPolicyTasks () {
axios.get(`/automation/${this.policypk}/policyautomatedtasks/`).then(r => {
this.automatedTasks = r.data;
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data);
});
getPolicyTasks() {
axios
.get(`/automation/${this.policypk}/policyautomatedtasks/`)
.then(r => {
this.automatedTasks = r.data;
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data);
});
}
},
computed: {
tasks () {
tasks() {
return this.automatedTasks.autotasks;
}
}

View File

@@ -38,18 +38,10 @@
<q-tr>
<!-- tds -->
<q-td>
<q-checkbox
disabled
dense
v-model="props.row.text_alert"
/>
<q-checkbox disabled dense v-model="props.row.text_alert" />
</q-td>
<q-td>
<q-checkbox
disabled
dense
v-model="props.row.email_alert"
/>
<q-checkbox disabled dense 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'">
@@ -84,14 +76,10 @@
<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"
>output</span>
<span style="cursor:pointer;color:blue;text-decoration:underline">output</span>
</q-td>
<q-td v-else-if="props.row.check_type === 'script'">
<span
style="cursor:pointer;color:blue;text-decoration:underline"
>output</span>
<span style="cursor:pointer;color:blue;text-decoration:underline">output</span>
</q-td>
<q-td v-else>{{ props.row.more_info }}</q-td>
<q-td>{{ props.row.last_run }}</q-td>
@@ -104,8 +92,8 @@
</template>
<script>
import axios from 'axios'
import mixins from '@/mixins/mixins'
import axios from "axios";
import mixins from "@/mixins/mixins";
export default {
name: "OverviewChecksTab",
@@ -138,23 +126,25 @@ export default {
}
};
},
mounted () {
mounted() {
this.getPolicyChecks();
},
watch: {
'policypk': function () {
policypk: function() {
this.getPolicyChecks();
}
},
methods: {
getPolicyChecks () {
axios.get(`/checks/${this.policypk}/loadpolicychecks/`).then(r => {
this.checks = r.data;
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data);
});
getPolicyChecks() {
axios
.get(`/checks/${this.policypk}/loadpolicychecks/`)
.then(r => {
this.checks = r.data;
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data);
});
}
},
computed: {

View File

@@ -2,7 +2,14 @@
<div v-if="Object.keys(automatedTasks).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 Task" text-color="black" @click="showAddAutomatedTask = true" />
<q-btn
size="sm"
color="grey-5"
icon="fas fa-plus"
label="Add Task"
text-color="black"
@click="showAddAutomatedTask = true"
/>
<q-btn dense flat push @click="refreshTasks(automatedTasks.pk)" icon="refresh" />
<template v-if="tasks === undefined || tasks.length === 0">
<p>No Tasks</p>
@@ -143,7 +150,7 @@ export default {
};
},
methods: {
taskEnableorDisable (pk, action) {
taskEnableorDisable(pk, action) {
const data = { enableordisable: action };
axios
.patch(`/automation/${pk}/automatedtasks/`, data)
@@ -153,14 +160,14 @@ export default {
})
.catch(e => this.notifyError("Something went wrong"));
},
refreshTasks (id) {
refreshTasks(id) {
this.$store.dispatch("automation/loadPolicyAutomatedTasks", id);
},
scriptMoreInfo (props) {
scriptMoreInfo(props) {
this.scriptInfo = props;
this.showScriptOutput = true;
},
runTask (pk, enabled) {
runTask(pk, enabled) {
if (!enabled) {
this.notifyError("Task cannot be run when it's disabled. Enable it first.");
return;
@@ -170,7 +177,7 @@ export default {
.then(r => this.notifySuccess(r.data))
.catch(() => this.notifyError("Something went wrong"));
},
deleteTask (name, pk) {
deleteTask(name, pk) {
this.$q
.dialog({
title: "Are you sure?",

View File

@@ -7,10 +7,7 @@
<q-tooltip content-class="bg-white text-primary">Close</q-tooltip>
</q-btn>
</q-bar>
<q-splitter
v-model="splitterModel"
style="height: 600px"
>
<q-splitter v-model="splitterModel" style="height: 600px">
<template v-slot:before>
<div class="q-pa-md">
<q-tree
@@ -21,9 +18,7 @@
selected-color="primary"
@update:selected="loadPolicyDetails"
default-expand-all
>
</q-tree>
></q-tree>
</div>
</template>
@@ -69,41 +64,44 @@
<script>
import axios from "axios";
import mixins from "@/mixins/mixins";
import OverviewChecksTab from "@/components/automation/OverviewChecksTab"
import OverviewAutomatedTasksTab from "@/components/automation/OverviewAutomatedTasksTab"
import OverviewChecksTab from "@/components/automation/OverviewChecksTab";
import OverviewAutomatedTasksTab from "@/components/automation/OverviewAutomatedTasksTab";
export default {
name: "PolicyOverview",
components: {
OverviewChecksTab,
OverviewAutomatedTasksTab,
OverviewAutomatedTasksTab
},
mixins: [mixins],
data () {
data() {
return {
splitterModel: 25,
selected: "",
selectedPolicy: {},
selectedTab: "checks",
clientSiteTree: [],
}
clientSiteTree: []
};
},
mounted () {
mounted() {
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);
});
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;}
loadPolicyDetails(key) {
if (key === undefined) {
return;
}
this.selectedPolicy = this.$refs.Tree.getNodeByKey(key);
},
processTreeDataFromApi(data) {
@@ -121,12 +119,11 @@ export default {
* }
* }
* }]
*/
*/
var result = [];
for (let client in data) {
var client_temp = {};
client_temp["label"] = client;
@@ -139,27 +136,26 @@ export default {
for (let policy in data[client].policies)
client_temp["children"].push({
label: data[client].policies[policy].name,
icon: 'policy',
icon: "policy",
id: data[client].policies[policy].id
});
}
// Iterate through Sites
for (let site in data[client].sites) {
var site_temp = {}
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',
icon: "policy",
id: data[client].sites[site].policies[policy].id
});
}
@@ -167,19 +163,17 @@ export default {
// 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;
}
},
computed: {
policypk () {
policypk() {
return this.selectedPolicy.id;
}
}

View File

@@ -27,20 +27,20 @@
</template>
<script>
import PolicyChecksTab from '@/components/automation/PolicyChecksTab';
import PolicyAutomatedTasksTab from '@/components/automation/PolicyAutomatedTasksTab';
import PolicyChecksTab from "@/components/automation/PolicyChecksTab";
import PolicyAutomatedTasksTab from "@/components/automation/PolicyAutomatedTasksTab";
export default {
name: "PolicySubTableTabs",
props: ["policypk"],
components: {
PolicyChecksTab,
PolicyAutomatedTasksTab,
PolicyAutomatedTasksTab
},
data () {
data() {
return {
subtab: 'checks'
}
subtab: "checks"
};
}
};
</script>

View File

@@ -27,18 +27,10 @@
<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>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey">
No Results
</q-item-section>
<q-item-section class="text-grey">No Results</q-item-section>
</q-item>
</template>
</q-select>
@@ -47,18 +39,10 @@
<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>
<template v-slot:no-option>
<q-item>
<q-item-section class="text-grey">
No Results
</q-item-section>
<q-item-section class="text-grey">No Results</q-item-section>
</q-item>
</template>
</q-select>
@@ -67,18 +51,10 @@
<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
>
<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-section class="text-grey">No Results</q-item-section>
</q-item>
</template>
</q-select>
@@ -98,8 +74,8 @@ import dropdown_formatter from "@/mixins/dropdown_formatter";
export default {
name: "PolicyForm",
mixins: [mixins, dropdown_formatter],
props: {"pk": Number},
data () {
props: { pk: Number },
data() {
return {
name: "",
desc: "",
@@ -109,18 +85,17 @@ export default {
selectedClients: [],
clientOptions: [],
siteOptions: [],
agentOptions: [],
agentOptions: []
};
},
computed: {
title () {
return (this.pk) ? "Edit Policy" : "Add Policy";
title() {
return this.pk ? "Edit Policy" : "Add Policy";
}
},
methods: {
getPolicy () {
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;
@@ -144,7 +119,7 @@ export default {
});
});
},
submit () {
submit() {
if (!this.name) {
this.notifyError("Name is required!");
return false;
@@ -160,9 +135,10 @@ export default {
sites: this.selectedSites.map(site => site.value),
clients: this.selectedClients.map(client => client.value)
};
if (this.pk) {
this.$store.dispatch("automation/editPolicy", this.pk, formData)
this.$store
.dispatch("automation/editPolicy", this.pk, formData)
.then(r => {
this.$q.loading.hide();
this.$emit("close");
@@ -173,10 +149,9 @@ export default {
this.$q.loading.hide();
this.notifyError(e.response.data);
});
} else {
this.$store.dispatch("automation/addPolicy", formData)
this.$store
.dispatch("automation/addPolicy", formData)
.then(r => {
this.$q.loading.hide();
this.$emit("close");
@@ -187,11 +162,11 @@ export default {
this.$q.loading.hide();
this.notifyError(e.response.data);
});
}
},
getClients () {
this.$store.dispatch("loadClients")
getClients() {
this.$store
.dispatch("loadClients")
.then(r => {
this.clientOptions = this.formatClient(r.data);
})
@@ -200,8 +175,9 @@ export default {
this.notifyError(e.response.data);
});
},
getSites () {
this.$store.dispatch("loadSites")
getSites() {
this.$store
.dispatch("loadSites")
.then(r => {
this.siteOptions = this.formatSites(r.data);
})
@@ -210,18 +186,19 @@ export default {
this.notifyError(e.response.data);
});
},
getAgents () {
this.$store.dispatch("loadAgents")
getAgents() {
this.$store
.dispatch("loadAgents")
.then(r => {
this.agentOptions = this.formatAgents(r.data)
this.agentOptions = this.formatAgents(r.data);
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data);
});
},
}
},
mounted () {
mounted() {
//If pk prop is set that means we are editting
if (this.pk) {
this.getPolicy();

View File

@@ -1,24 +1,10 @@
<template>
<q-card
style="min-width: 800px"
v-if="agentLoaded && clientsLoaded"
>
<q-card style="min-width: 800px" v-if="agentLoaded && clientsLoaded">
<q-splitter v-model="splitterModel">
<template v-slot:before>
<q-tabs
dense
v-model="tab"
vertical
class="text-primary"
>
<q-tab
name="general"
label="General"
/>
<q-tab
name="patch"
label="Patches"
/>
<q-tabs dense v-model="tab" vertical class="text-primary">
<q-tab name="general" label="General" />
<q-tab name="patch" label="Patches" />
</q-tabs>
</template>
<template v-slot:after>
@@ -26,18 +12,9 @@
<q-card-section class="row items-center">
<div class="text-h6">Edit {{ agent.hostname }}</div>
<q-space />
<q-btn
icon="close"
flat
round
dense
v-close-popup
/>
<q-btn icon="close" flat round dense v-close-popup />
</q-card-section>
<q-scroll-area
:thumb-style="thumbStyle"
style="height: 500px;"
>
<q-scroll-area :thumb-style="thumbStyle" style="height: 500px;">
<q-tab-panels
v-model="tab"
animated
@@ -61,13 +38,7 @@
<q-card-section class="row">
<div class="col-2">Site:</div>
<div class="col-2"></div>
<q-select
class="col-8"
dense
outlined
v-model="agent.site"
:options="sites"
/>
<q-select class="col-8" dense outlined v-model="agent.site" :options="sites" />
</q-card-section>
<q-card-section class="row">
<div class="col-2">Type:</div>
@@ -124,14 +95,8 @@
/>
</q-card-section>
<q-card-section class="row">
<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-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-tab-panel>
<!-- patch -->
@@ -317,15 +282,8 @@
</q-tab-panels>
</q-scroll-area>
<q-card-section class="row items-center">
<q-btn
label="Save"
color="primary"
type="submit"
/>
<q-btn
label="Cancel"
v-close-popup
/>
<q-btn label="Save" color="primary" type="submit" />
<q-btn label="Cancel" v-close-popup />
</q-card-section>
</q-form>
</template>
@@ -341,7 +299,7 @@ import { scheduledTimes } from "@/mixins/data";
export default {
name: "EditAgent",
mixins: [mixins],
data () {
data() {
return {
agentLoaded: false,
clientsLoaded: false,
@@ -366,19 +324,19 @@ export default {
};
},
methods: {
getAgentInfo () {
getAgentInfo() {
axios.get(`/agents/${this.selectedAgentPk}/agentdetail/`).then(r => {
this.agent = r.data;
this.agentLoaded = true;
});
},
getClientsSites () {
getClientsSites() {
axios.get("/clients/loadclients/").then(r => {
this.tree = r.data;
this.clientsLoaded = true;
});
},
editAgent () {
editAgent() {
let data = this.agent;
delete data.services;
delete data.disks;
@@ -396,13 +354,13 @@ export default {
},
computed: {
...mapGetters(["selectedAgentPk"]),
sites () {
sites() {
if (this.agentLoaded && this.clientsLoaded) {
return this.tree[this.agent.client];
}
}
},
created () {
created() {
this.getAgentInfo();
this.getClientsSites();
}

View File

@@ -10,37 +10,18 @@
<q-separator />
<q-card-section>
Select Version
<q-select
square
outlined
v-model="version"
:options="Object.values(versions)"
/>
<q-select square outlined v-model="version" :options="Object.values(versions)" />
</q-card-section>
<q-card-section v-show="version !== null">
Select Agent
<br />
<hr />
<q-checkbox
v-model="selectAll"
label="Select All"
@input="selectAllAction"
/>
<q-checkbox v-model="selectAll" label="Select All" @input="selectAllAction" />
<hr />
<q-option-group
v-model="group"
:options="agentOptions"
color="green"
type="checkbox"
/>
<q-option-group v-model="group" :options="agentOptions" color="green" type="checkbox" />
</q-card-section>
<q-card-section>
<q-btn
v-show="group.length !== 0"
label="Update"
color="primary"
@click="update"
/>
<q-btn v-show="group.length !== 0" label="Update" color="primary" @click="update" />
</q-card-section>
</q-card>
</template>

View File

@@ -8,14 +8,9 @@
</q-btn>
</q-bar>
<q-separator />
<q-card-section>All Alerts</q-card-section>
<q-card-section>
All Alerts
</q-card-section>
<q-card-section>
<q-btn
label="Update"
color="primary"
/>
<q-btn label="Update" color="primary" />
</q-card-section>
</q-card>
</template>
@@ -29,7 +24,7 @@ export default {
mixins: [mixins],
data() {
return {
alerts: [],
alerts: []
};
},
methods: {
@@ -38,17 +33,15 @@ export default {
axios
.get("/alerts/")
.then(r => {
this.alerts = r.data.alerts
this.alerts = r.data.alerts;
})
.catch(() => {
this.$q.loading.hide();
this.notifyError("Something went wrong");
});
},
},
computed: {
}
},
computed: {},
created() {
this.getAlerts();
}

View File

@@ -185,21 +185,13 @@ export default {
return r;
},
step1Done() {
return this.step > 1 && this.scriptPk !== null && this.taskName !== null
? true
: false;
return this.step > 1 && this.scriptPk !== null && this.taskName !== null ? true : false;
},
step2Done() {
if (this.trigger === "daily") {
return this.days !== null &&
this.days.length !== 0 &&
this.time !== null
? true
: false;
return this.days !== null && this.days.length !== 0 && this.time !== null ? true : false;
} else if (this.trigger === "checkfailure") {
return this.assignedCheck !== null && this.assignedCheck.length !== 0
? true
: false;
return this.assignedCheck !== null && this.assignedCheck.length !== 0 ? true : false;
} else if (this.trigger === "manual") {
return true;
} else {

View File

@@ -53,7 +53,7 @@ export default {
},
methods: {
addCheck() {
const pk = (this.policypk) ? {policy: this.policypk} : {pk: this.agentpk}
const pk = this.policypk ? { policy: this.policypk } : { pk: this.agentpk };
const data = {
...pk,

View File

@@ -3,23 +3,12 @@
<q-card-section class="row items-center">
<div class="text-h6">Add Disk Space Check</div>
<q-space />
<q-btn
icon="close"
flat
round
dense
v-close-popup
/>
<q-btn icon="close" flat round dense v-close-popup />
</q-card-section>
<q-form @submit.prevent="addCheck">
<q-card-section>
<q-select
outlined
v-model="firstdisk"
:options="disks"
label="Disk"
/>
<q-select outlined v-model="firstdisk" :options="disks" label="Disk" />
</q-card-section>
<q-card-section>
<q-input
@@ -43,15 +32,8 @@
/>
</q-card-section>
<q-card-actions align="right">
<q-btn
label="Add"
color="primary"
type="submit"
/>
<q-btn
label="Cancel"
v-close-popup
/>
<q-btn label="Add" color="primary" type="submit" />
<q-btn label="Cancel" v-close-popup />
</q-card-actions>
</q-form>
</q-card>
@@ -87,10 +69,9 @@ export default {
this.firstdisk = Object.keys(r.data)[0];
});
}
},
addCheck() {
const pk = (this.policypk) ? { policy: this.policypk } : { pk: this.agentpk }
const pk = this.policypk ? { policy: this.policypk } : { pk: this.agentpk };
const data = {
...pk,
check_type: "diskspace",

View File

@@ -53,7 +53,7 @@ export default {
},
methods: {
addCheck() {
const pk = (this.policypk) ? {policy: this.policypk} : {pk: this.agentpk}
const pk = this.policypk ? { policy: this.policypk } : { pk: this.agentpk };
const data = {
...pk,

View File

@@ -57,17 +57,18 @@ export default {
},
methods: {
addCheck() {
let pk = (this.policypk) ? {policy: this.policypk} : {pk: this.agentpk}
let pk = this.policypk ? { policy: this.policypk } : { pk: this.agentpk };
const data = {
...pk,
check_type: "ping",
failures: this.failure,
name: this.pingname,
ip: this.pingip,
ip: this.pingip
};
axios.post("/checks/addstandardcheck/", data)
axios
.post("/checks/addstandardcheck/", data)
.then(r => {
this.$emit("close");

View File

@@ -80,7 +80,7 @@ export default {
this.$store.dispatch("getScripts");
},
addScriptCheck() {
const pk = (this.policypk) ? {policy: this.policypk} : {pk: this.agentpk}
const pk = this.policypk ? { policy: this.policypk } : { pk: this.agentpk };
const data = {
...pk,
@@ -99,7 +99,7 @@ export default {
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
this.notifySuccess(r.data);
})
.catch(e => this.notifyError(e.response.data));

View File

@@ -3,13 +3,7 @@
<q-card-section class="row items-center">
<div class="text-h6">Add Windows Service Check</div>
<q-space />
<q-btn
icon="close"
flat
round
dense
v-close-popup
/>
<q-btn icon="close" flat round dense v-close-popup />
</q-card-section>
<q-form @submit.prevent="addCheck">
@@ -67,10 +61,7 @@
v-model="passIfStartPending"
label="PASS if service is in 'Start Pending' mode"
/>
<q-checkbox
v-model="restartIfStopped"
label="RESTART service if it's stopped"
/>
<q-checkbox v-model="restartIfStopped" label="RESTART service if it's stopped" />
</q-card-section>
<q-card-section>
<q-select
@@ -82,15 +73,8 @@
/>
</q-card-section>
<q-card-actions align="right">
<q-btn
label="Add"
color="primary"
type="submit"
/>
<q-btn
label="Cancel"
v-close-popup
/>
<q-btn label="Add" color="primary" type="submit" />
<q-btn label="Cancel" v-close-popup />
</q-card-actions>
</q-form>
</q-card>
@@ -136,31 +120,35 @@ export default {
}
},
getRawName() {
let svc = this.servicesData.find(
k => k.display_name === this.displayName
);
let svc = this.servicesData.find(k => k.display_name === this.displayName);
this.rawName = [svc].map(j => j.name);
},
addCheck() {
const pk = (this.policypk) ? { policy: this.policypk } : { pk: this.agentpk }
const pk = this.policypk ? { policy: this.policypk } : { pk: this.agentpk };
let rawname, displayname;
if (this.policypk) {
// policy
if (this.serviceType === 'svcdefault') {
rawname = { rawname: this.rawName[0] }
displayname = { displayname: this.displayName }
if (this.rawName.length === 0) { this.notifyError("Please select a service"); return; }
} else if (this.serviceType === 'svcmanual') {
rawname = { rawname: this.manualServiceName }
displayname = { displayname: this.manualSvcDisplayName }
if (!this.manualServiceName || !this.manualSvcDisplayName) { this.notifyError("All fields required"); return; }
if (this.serviceType === "svcdefault") {
rawname = { rawname: this.rawName[0] };
displayname = { displayname: this.displayName };
if (this.rawName.length === 0) {
this.notifyError("Please select a service");
return;
}
} else if (this.serviceType === "svcmanual") {
rawname = { rawname: this.manualServiceName };
displayname = { displayname: this.manualSvcDisplayName };
if (!this.manualServiceName || !this.manualSvcDisplayName) {
this.notifyError("All fields required");
return;
}
}
} else {
// agent
rawname = { rawname: this.rawName[0] }
displayname = { displayname: this.displayName }
rawname = { rawname: this.rawName[0] };
displayname = { displayname: this.displayName };
}
const data = {

View File

@@ -53,12 +53,10 @@ export default {
},
methods: {
getCheck() {
axios
.get(`/checks/getstandardcheck/cpuload/${this.editCheckPK}/`)
.then(r => {
this.threshold = r.data.cpuload;
this.failure = r.data.failures;
});
axios.get(`/checks/getstandardcheck/cpuload/${this.editCheckPK}/`).then(r => {
this.threshold = r.data.cpuload;
this.failure = r.data.failures;
});
},
editCheck() {
const data = {
@@ -77,7 +75,7 @@ export default {
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
this.notifySuccess("CPU load check was edited!");
})
.catch(e => this.notifyError(e.response.data.error));

View File

@@ -57,14 +57,12 @@ export default {
},
methods: {
getCheck() {
axios
.get(`/checks/getstandardcheck/diskspace/${this.editCheckPK}/`)
.then(r => {
this.disks = [r.data.disk];
this.diskToEdit = r.data.disk;
this.threshold = r.data.threshold;
this.failure = r.data.failures;
});
axios.get(`/checks/getstandardcheck/diskspace/${this.editCheckPK}/`).then(r => {
this.disks = [r.data.disk];
this.diskToEdit = r.data.disk;
this.threshold = r.data.threshold;
this.failure = r.data.failures;
});
},
editCheck() {
const data = {

View File

@@ -75,7 +75,7 @@ export default {
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
this.notifySuccess("Memory check was edited!");
})
.catch(e => this.notifyError(e.response.data.error));

View File

@@ -57,13 +57,11 @@ export default {
},
methods: {
getCheck() {
axios
.get(`/checks/getstandardcheck/ping/${this.editCheckPK}/`)
.then(r => {
this.failure = r.data.failures;
this.pingname = r.data.name;
this.pingip = r.data.ip;
});
axios.get(`/checks/getstandardcheck/ping/${this.editCheckPK}/`).then(r => {
this.failure = r.data.failures;
this.pingname = r.data.name;
this.pingip = r.data.ip;
});
},
editCheck() {
const data = {
@@ -83,7 +81,7 @@ export default {
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
this.notifySuccess("Ping check was edited!");
})
.catch(e => this.notifyError(e.response.data.error));

View File

@@ -57,13 +57,11 @@ export default {
},
methods: {
getScriptCheck() {
axios
.get(`/checks/getstandardcheck/script/${this.editCheckPK}/`)
.then(r => {
this.failure = r.data.failures;
this.timeout = r.data.timeout;
this.scriptName = r.data.script.name;
});
axios.get(`/checks/getstandardcheck/script/${this.editCheckPK}/`).then(r => {
this.failure = r.data.failures;
this.timeout = r.data.timeout;
this.scriptName = r.data.script.name;
});
},
editScriptCheck() {
const data = {
@@ -82,7 +80,7 @@ export default {
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
this.notifySuccess(r.data);
})
.catch(e => this.notifyError(e.response.data.error));

View File

@@ -7,13 +7,21 @@
</q-card-section>
<q-form @submit.prevent="editCheck">
<q-card-section>
<q-select disable dense outlined v-model="displayName" :options="svcDisplayNames" label="Service" />
<q-select
disable
dense
outlined
v-model="displayName"
:options="svcDisplayNames"
label="Service"
/>
</q-card-section>
<q-card-section>
<q-checkbox v-model="passIfStartPending" label="PASS if service is in 'Start Pending' mode" />
<q-checkbox
v-model="passIfStartPending"
label="PASS if service is in 'Start Pending' mode"
/>
<q-checkbox v-model="restartIfStopped" label="RESTART service if it's stopped" />
</q-card-section>
<q-card-section>
@@ -82,7 +90,7 @@ export default {
} else {
this.$store.dispatch("loadChecks", this.agentpk);
}
this.notifySuccess("Windows service check was edited!");
})
.catch(e => this.notifyError(e.response.data.error));
@@ -90,6 +98,6 @@ export default {
},
mounted() {
this.getService();
},
}
};
</script>

View File

@@ -10,49 +10,40 @@
>
<q-card class="bg-grey-10 text-white">
<q-bar>
<q-btn @click="getLog" class="q-mr-sm" dense flat push icon="refresh" label="Refresh" />
Debug Log
<q-btn @click="getLog" class="q-mr-sm" dense flat push icon="refresh" label="Refresh" />Debug Log
<q-space />
<q-btn color="primary" text-color="white" label="Download log" @click="downloadLog" />
<q-space />
<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-md row">
<div class="col-2">
<q-select
dark
dense
outlined
v-model="agent"
:options="agents"
label="Filter Agent"
@input="getLog"
/>
<q-select
dark
dense
outlined
v-model="agent"
:options="agents"
label="Filter Agent"
@input="getLog"
/>
</div>
<div class="col-1">
<q-select
dark
dense
outlined
v-model="order"
:options="orders"
label="Order"
@input="getLog"
/>
<q-select
dark
dense
outlined
v-model="order"
:options="orders"
label="Order"
@input="getLog"
/>
</div>
</div>
<q-card-section>
<q-radio
dark
v-model="loglevel"
color="cyan"
val="info"
label="Info"
@input="getLog"
/>
<q-radio dark v-model="loglevel" color="cyan" val="info" label="Info" @input="getLog" />
<q-radio
dark
v-model="loglevel"
@@ -61,14 +52,7 @@
label="Critical"
@input="getLog"
/>
<q-radio
dark
v-model="loglevel"
color="red"
val="error"
label="Error"
@input="getLog"
/>
<q-radio dark v-model="loglevel" color="red" val="error" label="Error" @input="getLog" />
<q-radio
dark
v-model="loglevel"
@@ -80,12 +64,12 @@
</q-card-section>
<q-separator />
<q-card-section>
<q-scroll-area
<q-scroll-area
:thumb-style="{ right: '4px', borderRadius: '5px', background: 'red', width: '10px', opacity: 1 }"
style="height: 60vh;"
>
<pre>{{ logContent }}</pre>
</q-scroll-area>
>
<pre>{{ logContent }}</pre>
</q-scroll-area>
</q-card-section>
</q-card>
</q-dialog>
@@ -94,7 +78,7 @@
<script>
import axios from "axios";
import { mapState } from 'vuex';
import { mapState } from "vuex";
export default {
name: "LogModal",
data() {
@@ -109,15 +93,16 @@ export default {
},
methods: {
downloadLog() {
axios.get("/api/v1/downloadrmmlog/", { responseType: 'blob' })
axios
.get("/api/v1/downloadrmmlog/", { responseType: "blob" })
.then(({ data }) => {
const blob = new Blob([data], { type: 'text/plain' })
let link = document.createElement('a')
link.href = window.URL.createObjectURL(blob)
link.download = 'debug.log'
link.click()
const blob = new Blob([data], { type: "text/plain" });
let link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);
link.download = "debug.log";
link.click();
})
.catch(error => console.error(error))
.catch(error => console.error(error));
},
getLog() {
axios.get(`/api/v1/getrmmlog/${this.loglevel}/${this.agent}/${this.order}/`).then(r => {

View File

@@ -80,7 +80,7 @@ export default {
this.name = r.data.name;
this.desc = r.data.description;
this.shell = r.data.shell;
})
});
},
editScript() {
if (!this.name || !this.shell) {

View File

@@ -35,7 +35,7 @@ router.beforeEach((to, from, next) => {
});
axios.interceptors.request.use(
function(config) {
function (config) {
const token = store.state.token;
if (token != null) {
@@ -44,19 +44,19 @@ axios.interceptors.request.use(
return config;
},
function(err) {
function (err) {
return Promise.reject(err);
}
);
axios.interceptors.response.use(
function(response) {
function (response) {
if (response.status === 400) {
return Promise.reject(response);
}
return response;
},
function(error) {
function (error) {
if (error.response.status === 401) {
router.push({ path: "/expired" });
}

View File

@@ -1,6 +1,6 @@
export default {
methods: {
formatClients (clients) {
formatClients(clients) {
return clients.map(client => {
return {
label: client.client,
@@ -8,7 +8,7 @@ export default {
};
});
},
formatSites (sites) {
formatSites(sites) {
return sites.map(site => {
return {
label: `${site.client_name}\\${site.site}`,
@@ -16,7 +16,7 @@ export default {
};
});
},
formatAgents (agents) {
formatAgents(agents) {
return agents.map(agent => {
return {
label: `${agent.client}\\${agent.site}\\${agent.hostname}`,

View File

@@ -6,7 +6,7 @@ export default {
alerts: [],
},
getters:{
getters: {
getAlerts(state) {
return state.alerts;
},

View File

@@ -9,56 +9,56 @@ export default {
policies: [],
},
getters:{
selectedPolicyPk (state) {
getters: {
selectedPolicyPk(state) {
return state.selectedPolicy;
},
policies (state) {
policies(state) {
return state.policies;
}
},
mutations: {
SET_POLICIES (state, policies) {
SET_POLICIES(state, policies) {
state.policies = policies;
},
setSelectedPolicy (state, pk) {
setSelectedPolicy(state, pk) {
state.selectedPolicy = pk;
},
setPolicyChecks (state, checks) {
setPolicyChecks(state, checks) {
state.checks = checks;
},
setPolicyAutomatedTasks (state, tasks) {
setPolicyAutomatedTasks(state, tasks) {
state.automatedTasks = tasks;
},
},
actions: {
loadPolicies (context) {
loadPolicies(context) {
axios.get("/automation/policies/").then(r => {
context.commit("SET_POLICIES", r.data);
})
},
loadPolicyAutomatedTasks (context, pk) {
loadPolicyAutomatedTasks(context, pk) {
axios.get(`/automation/${pk}/policyautomatedtasks/`).then(r => {
context.commit("setPolicyAutomatedTasks", r.data);
});
},
loadPolicyChecks (context, pk) {
loadPolicyChecks(context, pk) {
axios.get(`/checks/${pk}/loadpolicychecks/`).then(r => {
context.commit("setPolicyChecks", r.data);
});
},
loadPolicy (context, pk) {
loadPolicy(context, pk) {
return axios.get(`/automation/policies/${pk}/`);
},
addPolicy (context, data) {
addPolicy(context, data) {
return axios.post("/automation/policies/", data);
},
editpolicy (context, data) {
editpolicy(context, data) {
return axios.put(`/automation/policies/${this.pk}/`, formData)
},
deletePolicy (context, pk) {
deletePolicy(context, pk) {
return axios.delete(`/automation/policies/${pk}`).then(r => {
context.dispatch("getPolicies");
});

View File

@@ -6,6 +6,6 @@ export default {
mutations: {
TOGGLE_LOG_MODAL(state, action) {
state.toggleLogModal = action;
}
}
}
}

View File

@@ -63,7 +63,7 @@ export const store = new Vuex.Store({
},
},
mutations: {
TOGGLE_SCRIPT_MANAGER (state, action) {
TOGGLE_SCRIPT_MANAGER(state, action) {
state.toggleScriptManager = action;
},
AGENT_TABLE_LOADING(state, visible) {
@@ -149,13 +149,13 @@ export const store = new Vuex.Store({
context.commit("getUpdatedSites", r.data);
});
},
loadClients (context) {
loadClients(context) {
return axios.get("/clients/listclients/");
},
loadSites (context) {
loadSites(context) {
return axios.get("/clients/listsites/");
},
loadAgents (context) {
loadAgents(context) {
return axios.get("/agents/listagents/");
},
loadTree({ commit }) {

View File

@@ -67,24 +67,27 @@ export default {
this.notifyError("Please upload your meshagent.exe");
} else {
this.$q.loading.show();
const data = {client: this.firstclient, site: this.firstsite};
axios.post("/clients/initialsetup/", data).then(r => {
let formData = new FormData();
formData.append("meshagent", this.meshagent);
axios.put("/api/v1/uploadmeshagent/", formData).then(r => {
this.$q.loading.hide();
this.$router.push({ name: "Dashboard" });
const data = { client: this.firstclient, site: this.firstsite };
axios
.post("/clients/initialsetup/", data)
.then(r => {
let formData = new FormData();
formData.append("meshagent", this.meshagent);
axios
.put("/api/v1/uploadmeshagent/", formData)
.then(r => {
this.$q.loading.hide();
this.$router.push({ name: "Dashboard" });
})
.catch(e => {
this.notifyError("error uploading");
this.$q.loading.hide();
});
})
.catch(e => {
this.notifyError('error uploading');
.catch(err => {
this.notifyError(err.response.data.error);
this.$q.loading.hide();
})
})
.catch(err => {
this.notifyError(err.response.data.error);
this.$q.loading.hide();
})
});
}
}
}

View File

@@ -9,10 +9,7 @@
</div>
</q-card-section>
<q-card-section>
<q-form
@submit.prevent="checkCreds"
class="q-gutter-md"
>
<q-form @submit.prevent="checkCreds" class="q-gutter-md">
<q-input
filled
v-model="credentials.username"
@@ -31,11 +28,7 @@
/>
<div>
<q-btn
label="Login"
type="submit"
color="primary"
/>
<q-btn label="Login" type="submit" color="primary" />
</div>
</q-form>
</q-card-section>
@@ -55,20 +48,9 @@
/>
</q-card-section>
<q-card-actions
align="right"
class="text-primary"
>
<q-btn
flat
label="Cancel"
v-close-popup
/>
<q-btn
flat
label="Submit"
type="submit"
/>
<q-card-actions align="right" class="text-primary">
<q-btn flat label="Cancel" v-close-popup />
<q-btn flat label="Submit" type="submit" />
</q-card-actions>
</q-form>
</q-card>
@@ -94,13 +76,14 @@ export default {
methods: {
checkCreds() {
axios.post("/checkcreds/", this.credentials)
axios
.post("/checkcreds/", this.credentials)
.then(r => {
this.prompt = true;
})
.catch(() => {
this.notifyError('Bad credentials')
})
this.notifyError("Bad credentials");
});
},
onSubmit() {
this.$store
@@ -124,11 +107,6 @@ export default {
<style>
.bg-image {
background-image: linear-gradient(
90deg,
rgba(20, 20, 29, 1) 0%,
rgba(38, 42, 56, 1) 49%,
rgba(15, 18, 20, 1) 100%
);
background-image: linear-gradient(90deg, rgba(20, 20, 29, 1) 0%, rgba(38, 42, 56, 1) 49%, rgba(15, 18, 20, 1) 100%);
}
</style>

View File

@@ -1,16 +1,15 @@
<template>
<div class="fixed-center text-center">
<p class="text-faded">Sorry, nothing here...<strong>(404)</strong></p>
<q-btn
color="secondary"
style="width:200px;"
@click="$router.push('/')"
>Go back</q-btn>
<p class="text-faded">
Sorry, nothing here...
<strong>(404)</strong>
</p>
<q-btn color="secondary" style="width:200px;" @click="$router.push('/')">Go back</q-btn>
</div>
</template>
<script>
export default {
name: "NotFound"
}
name: "NotFound"
};
</script>

View File

@@ -21,9 +21,11 @@
<q-tab-panel name="terminal">
<iframe
style="overflow:hidden;height:715px;"
:src="terminalurl" width="100%" height="100%" scrolling="no"
>
</iframe>
:src="terminalurl"
width="100%"
height="100%"
scrolling="no"
></iframe>
</q-tab-panel>
<q-tab-panel name="processes">
<ProcessManager :pk="pk" />
@@ -37,9 +39,11 @@
<q-tab-panel name="filebrowser">
<iframe
style="overflow:hidden;height:715px;"
:src="fileurl" width="100%" height="100%" scrolling="no"
>
</iframe>
:src="fileurl"
width="100%"
height="100%"
scrolling="no"
></iframe>
</q-tab-panel>
</q-tab-panels>
</div>
@@ -63,7 +67,7 @@ export default {
terminalurl: "",
fileurl: "",
tab: "terminal",
title: ''
title: ""
};
},
methods: {
@@ -78,7 +82,7 @@ export default {
meta() {
return {
title: this.title
}
};
},
computed: {
pk() {

View File

@@ -1,29 +1,31 @@
<template>
<iframe
style="overflow:hidden;height:900px;"
:src="takeControlUrl" width="100%" height="100%" scrolling="no"
>
</iframe>
:src="takeControlUrl"
width="100%"
height="100%"
scrolling="no"
></iframe>
</template>
<script>
import axios from 'axios';
import axios from "axios";
export default {
name: "TakeControl",
data() {
return {
takeControlUrl: ''
}
},
methods: {
genURL() {
const pk = this.$route.params.pk
axios.get(`/agents/${pk}/takecontrol/`).then(r => this.takeControlUrl = r.data)
}
},
created() {
this.genURL()
name: "TakeControl",
data() {
return {
takeControlUrl: ""
};
},
methods: {
genURL() {
const pk = this.$route.params.pk;
axios.get(`/agents/${pk}/takecontrol/`).then(r => (this.takeControlUrl = r.data));
}
}
},
created() {
this.genURL();
}
};
</script>

View File

@@ -15,7 +15,7 @@ describe('AutomationManager.vue', () => {
desc: "Description",
active: true,
clients: [],
sites: [{},{}],
sites: [{}, {}],
agents: [{}]
},
{
@@ -24,7 +24,7 @@ describe('AutomationManager.vue', () => {
desc: "Description 2",
active: false,
clients: [],
sites: [{},{}],
sites: [{}, {}],
agents: [{}]
}
];
@@ -45,7 +45,7 @@ describe('AutomationManager.vue', () => {
};
mutations = {
setSelectedPolicy: jest.fn((state, key) => {state.selectedPolicy = key}),
setSelectedPolicy: jest.fn((state, key) => { state.selectedPolicy = key }),
setPolicyChecks: jest.fn(),
setPolicyAutomatedTasks: jest.fn(),
@@ -74,14 +74,14 @@ describe('AutomationManager.vue', () => {
store,
localVue,
stubs: [
"PolicySubTableTabs",
"PolicySubTableTabs",
"PolicyForm"
],
});
});
// Runs after every test
// This is needed to remove q-dialogs since body doesn't rerender
afterEach(() => {
@@ -107,7 +107,7 @@ describe('AutomationManager.vue', () => {
it("sends vuex mutations and actions when policy is selected", () => {
const row = wrapper.findAll("tbody > tr.q-tr").wrappers[1];
row.trigger('click');
expect(mutations.setSelectedPolicy).toHaveBeenCalledWith(expect.anything(), 2);
@@ -118,7 +118,7 @@ describe('AutomationManager.vue', () => {
it("shows edit policy modal on edit button press", async () => {
const button = wrapper.find({ref: "edit"});
const button = wrapper.find({ ref: "edit" });
expect(bodyWrapper.find(".q-dialog").exists()).toBe(false);
await button.trigger("click")
@@ -133,7 +133,7 @@ describe('AutomationManager.vue', () => {
it('shows add policy modal on button press', async () => {
const button = wrapper.find({ref: "new"});
const button = wrapper.find({ ref: "new" });
expect(bodyWrapper.find(".q-dialog").exists()).toBe(false);
await button.trigger("click");
@@ -143,7 +143,7 @@ describe('AutomationManager.vue', () => {
it('deletes selected policy', async () => {
const button = wrapper.find({ref: "delete"});
const button = wrapper.find({ ref: "delete" });
expect(bodyWrapper.find(".q-dialog").exists()).toBe(false);
// Select Row
@@ -160,7 +160,7 @@ describe('AutomationManager.vue', () => {
it('shows overview modal when button clicked', async () => {
const button = wrapper.find({ref: "overview"});
const button = wrapper.find({ ref: "overview" });
expect(bodyWrapper.find(".q-dialog").exists()).toBe(false);
await button.trigger("click");
@@ -169,7 +169,7 @@ describe('AutomationManager.vue', () => {
it('calls vuex loadPolicies action when refresh button clicked and clears selected', () => {
const button = wrapper.find({ref: "refresh"});
const button = wrapper.find({ ref: "refresh" });
button.trigger("click");
expect(actions.loadPolicies).toHaveBeenCalled();
@@ -180,4 +180,3 @@ describe('AutomationManager.vue', () => {
});
});

View File

@@ -20,13 +20,13 @@ describe('PolicyForm.vue', () => {
beforeEach(() => {
rootActions = {
loadClients: jest.fn( () => clients ),
loadSites: jest.fn( () => sites ),
loadAgents: jest.fn( () => agents ),
loadClients: jest.fn(() => clients),
loadSites: jest.fn(() => sites),
loadAgents: jest.fn(() => agents),
};
actions = {
loadPolicy: jest.fn( () => policy ),
loadPolicy: jest.fn(() => policy),
addPolicy: jest.fn(),
editPolicy: jest.fn(),
};
@@ -82,4 +82,3 @@ describe('PolicyForm.vue', () => {
})*/
})