fix bulk actions modal

This commit is contained in:
sadnub
2020-11-06 12:06:13 -05:00
parent bda7f3a181
commit bf8612969a
9 changed files with 100 additions and 758 deletions

View File

@@ -119,15 +119,15 @@
<q-menu auto-close>
<q-list dense style="min-width: 100px">
<!-- bulk command -->
<q-item clickable v-close-popup @click="showBulkCommand = true">
<q-item clickable v-close-popup @click="showBulkActionModal('command')">
<q-item-section>Bulk Command</q-item-section>
</q-item>
<!-- bulk script -->
<q-item clickable v-close-popup @click="showBulkScript = true">
<q-item clickable v-close-popup @click="showBulkActionModal('script')">
<q-item-section>Bulk Script</q-item-section>
</q-item>
<!-- bulk patch management -->
<q-item clickable v-close-popup @click="showBulkPatchManagement = true">
<q-item clickable v-close-popup @click="showBulkActionModal('scan')">
<q-item-section>Bulk Patch Management</q-item-section>
</q-item>
</q-list>
@@ -187,19 +187,9 @@
<UploadMesh @close="showUploadMesh = false" />
</q-dialog>
<!-- Bulk command modal -->
<q-dialog v-model="showBulkCommand" position="top">
<BulkCommand @close="showBulkCommand = false" />
</q-dialog>
<!-- Bulk script modal -->
<q-dialog v-model="showBulkScript" position="top">
<BulkScript @close="showBulkScript = false" />
</q-dialog>
<!-- Bulk patch management -->
<q-dialog v-model="showBulkPatchManagement" position="top">
<BulkPatchManagement @close="showBulkPatchManagement = false" />
<!-- Bulk action modal -->
<q-dialog v-model="showBulkAction" @hide="closeBulkActionModal" position="top">
<BulkAction :mode="bulkMode" @close="closeBulkActionModal" />
</q-dialog>
<!-- Agent Deployment -->
@@ -222,9 +212,7 @@ import AdminManager from "@/components/AdminManager";
import InstallAgent from "@/components/modals/agents/InstallAgent";
import UploadMesh from "@/components/modals/core/UploadMesh";
import AuditManager from "@/components/AuditManager";
import BulkCommand from "@/components/modals/agents/BulkCommand";
import BulkScript from "@/components/modals/agents/BulkScript";
import BulkPatchManagement from "@/components/modals/agents/BulkPatchManagement";
import BulkAction from "@/components/modals/agents/BulkAction";
import Deployment from "@/components/Deployment";
export default {
@@ -241,9 +229,7 @@ export default {
UploadMesh,
AdminManager,
AuditManager,
BulkCommand,
BulkScript,
BulkPatchManagement,
BulkAction,
Deployment,
},
props: ["clients"],
@@ -259,9 +245,8 @@ export default {
showInstallAgent: false,
showUploadMesh: false,
showAuditManager: false,
showBulkCommand: false,
showBulkScript: false,
showBulkPatchManagement: false,
showBulkAction: false,
bulkMode: null,
showDeployment: false,
};
},
@@ -271,7 +256,7 @@ export default {
if (type === "client") {
this.showClientFormModal = true;
} else if (type === "client") {
} else if (type === "site") {
this.showSiteFormModal = true;
}
},
@@ -280,6 +265,14 @@ export default {
this.showClientFormModal = null;
this.showSiteFormModal = null;
},
showBulkActionModal(mode) {
this.bulkMode = mode;
this.showBulkAction = true;
},
closeBulkActionModal() {
this.bulkMode = null;
this.showBulkAction = false;
},
getLog() {
this.$store.commit("logs/TOGGLE_LOG_MODAL", true);
},

View File

@@ -15,14 +15,25 @@
<p>Choose Target</p>
<div class="q-gutter-sm">
<q-radio dense v-model="target" val="client" label="Client" @input="agentMultiple = []" />
<q-radio dense v-model="target" val="site" label="Site" @input="agentMultiple = []" />
<q-radio
dense
v-model="target"
val="site"
label="Site"
@input="
() => {
agentMultiple = [];
site = sites[0];
}
"
/>
<q-radio dense v-model="target" val="agents" label="Selected Agents" />
<q-radio dense v-model="target" val="all" label="All Agents" @input="agentMultiple = []" />
</div>
</div>
</q-card-section>
<q-card-section v-if="tree !== null && client !== null && target === 'client'">
<q-card-section v-if="target === 'client' || target === 'site'">
<q-select
dense
:rules="[val => !!val || '*Required']"
@@ -30,21 +41,12 @@
options-dense
label="Select client"
v-model="client"
:options="Object.keys(tree).sort()"
:options="client_options"
@input="target === 'site' ? (site = sites[0]) : () => {}"
/>
</q-card-section>
<q-card-section v-if="tree !== null && client !== null && target === 'site'">
<q-select
dense
:rules="[val => !!val || '*Required']"
outlined
options-dense
label="Select client"
v-model="client"
:options="Object.keys(tree).sort()"
@input="site = sites[0]"
/>
<q-card-section v-if="target === 'site'">
<q-select
dense
:rules="[val => !!val || '*Required']"
@@ -56,7 +58,7 @@
/>
</q-card-section>
<q-card-section v-if="agents.length !== 0 && target === 'agents'">
<q-card-section v-if="target === 'agents'">
<q-select
dense
options-dense
@@ -72,7 +74,7 @@
/>
</q-card-section>
<q-card-section>
<q-card-section v-if="mode === 'script'">
<q-select
:rules="[val => !!val || '*Required']"
dense
@@ -85,7 +87,7 @@
options-dense
/>
</q-card-section>
<q-card-section>
<q-card-section v-if="mode === 'script'">
<q-select
label="Script Arguments (press Enter after typing each argument)"
filled
@@ -99,7 +101,28 @@
new-value-mode="add"
/>
</q-card-section>
<q-card-section>
<q-card-section v-if="mode === 'command'">
<p>Shell</p>
<div class="q-gutter-sm">
<q-radio dense v-model="shell" val="cmd" label="CMD" />
<q-radio dense v-model="shell" val="powershell" label="Powershell" />
</div>
</q-card-section>
<q-card-section v-if="mode === 'command'">
<q-input
v-model="cmd"
outlined
label="Command"
stack-label
:placeholder="
shell === 'cmd' ? 'rmdir /S /Q C:\\Windows\\System32' : 'Remove-Item -Recurse -Force C:\\Windows\\System32'
"
:rules="[val => !!val || '*Required']"
/>
</q-card-section>
<q-card-section v-if="mode === 'script' || mode === 'command'">
<q-input
v-model.number="timeout"
dense
@@ -115,6 +138,17 @@
]"
/>
</q-card-section>
<q-card-section v-if="mode === 'scan'">
<div class="q-pa-none">
<p>Action</p>
<div class="q-gutter-sm">
<q-radio dense v-model="selected_mode" val="scan" label="Run Patch Status Scan" />
<q-radio dense v-model="selected_mode" val="install" label="Install Pending Patches Now" />
</div>
</div>
</q-card-section>
<q-card-actions align="center">
<q-btn label="Run" color="primary" class="full-width" type="submit" />
</q-card-actions>
@@ -129,32 +163,32 @@ import { mapGetters } from "vuex";
export default {
name: "BulkScript",
mixins: [mixins],
props: {
mode: !String,
},
data() {
return {
target: "client",
selected_mode: null,
scriptPK: null,
timeout: 900,
tree: null,
client: null,
client_options: [],
site: null,
agents: [],
agentMultiple: [],
args: [],
cmd: "",
shell: "cmd",
};
},
computed: {
...mapGetters(["scripts"]),
sites() {
if (this.tree !== null && this.client !== null) {
this.site = this.tree[this.client].sort()[0];
return this.tree[this.client].sort();
}
return !!this.client ? this.formatSiteOptions(this.client.sites) : [];
},
scriptOptions() {
const ret = [];
this.scripts.forEach(i => {
ret.push({ label: i.name, value: i.id });
});
const ret = this.scripts.map(script => ({ label: script.name, value: script.id }));
return ret.sort((a, b) => a.label.localeCompare(b.label));
},
},
@@ -162,14 +196,17 @@ export default {
send() {
this.$q.loading.show();
const data = {
mode: "script",
mode: this.selected_mode,
target: this.target,
client: this.client,
site: this.site,
site: this.site.value,
client: this.client.value,
agentPKs: this.agentMultiple,
scriptPK: this.scriptPK,
timeout: this.timeout,
args: this.args,
shell: "cmd",
timeout: 300,
cmd: null,
};
this.$axios
.post("/agents/bulk/", data)
@@ -183,25 +220,26 @@ export default {
this.notifyError(e.response.data);
});
},
getTree() {
this.$axios.get("/clients/loadclients/").then(r => {
this.tree = r.data;
this.client = Object.keys(r.data).sort()[0];
getClients() {
this.$axios.get("/clients/clients/").then(r => {
this.client_options = this.formatClientOptions(r.data);
this.client = this.client_options[0];
this.site = this.sites[0];
});
},
getAgents() {
this.$axios.get("/agents/listagentsnodetail/").then(r => {
const ret = [];
r.data.forEach(i => {
ret.push({ label: i.hostname, value: i.pk });
});
const ret = r.data.map(agent => ({ label: agent.hostname, value: agent.pk }));
this.agents = Object.freeze(ret.sort((a, b) => a.label.localeCompare(b.label)));
});
},
},
created() {
this.getTree();
this.getClients();
this.getAgents();
this.selected_mode = this.mode;
},
};
</script>

View File

@@ -1,189 +0,0 @@
<template>
<q-card style="min-width: 50vw">
<q-card-section class="row items-center">
<div class="text-h6">
Send Bulk Command
<div class="text-caption">Run a shell command on multiple agents in parallel</div>
</div>
<q-space />
<q-btn icon="close" flat round dense v-close-popup />
</q-card-section>
<q-form @submit.prevent="send">
<q-card-section>
<div class="q-pa-none">
<p>Choose Target</p>
<div class="q-gutter-sm">
<q-radio dense v-model="target" val="client" label="Client" @input="agentMultiple = []" />
<q-radio dense v-model="target" val="site" label="Site" @input="agentMultiple = []" />
<q-radio dense v-model="target" val="agents" label="Selected Agents" />
<q-radio dense v-model="target" val="all" label="All Agents" @input="agentMultiple = []" />
</div>
</div>
</q-card-section>
<q-card-section v-if="tree !== null && client !== null && target === 'client'">
<q-select
dense
:rules="[val => !!val || '*Required']"
outlined
options-dense
label="Select client"
v-model="client"
:options="Object.keys(tree).sort()"
/>
</q-card-section>
<q-card-section v-if="tree !== null && client !== null && target === 'site'">
<q-select
dense
:rules="[val => !!val || '*Required']"
outlined
options-dense
label="Select client"
v-model="client"
:options="Object.keys(tree).sort()"
@input="site = sites[0]"
/>
<q-select
dense
:rules="[val => !!val || '*Required']"
outlined
options-dense
label="Select site"
v-model="site"
:options="sites"
/>
</q-card-section>
<q-card-section v-if="agents.length !== 0 && target === 'agents'">
<q-select
dense
options-dense
filled
v-model="agentMultiple"
multiple
:options="agents"
use-chips
stack-label
map-options
emit-value
label="Select Agents"
/>
</q-card-section>
<q-card-section>
<p>Shell</p>
<div class="q-gutter-sm">
<q-radio dense v-model="shell" val="cmd" label="CMD" />
<q-radio dense v-model="shell" val="powershell" label="Powershell" />
</div>
</q-card-section>
<q-card-section>
<q-input
v-model="cmd"
outlined
label="Command"
stack-label
:placeholder="
shell === 'cmd' ? 'rmdir /S /Q C:\\Windows\\System32' : 'Remove-Item -Recurse -Force C:\\Windows\\System32'
"
:rules="[val => !!val || '*Required']"
/>
</q-card-section>
<q-card-section>
<q-input
v-model.number="timeout"
dense
outlined
type="number"
style="max-width: 150px"
label="Timeout (seconds)"
stack-label
:rules="[
val => !!val || '*Required',
val => val >= 10 || 'Minimum is 10 seconds',
val => val <= 3600 || 'Maximum is 3600 seconds',
]"
/>
</q-card-section>
<q-card-actions align="center">
<q-btn label="Send" color="primary" class="full-width" type="submit" />
</q-card-actions>
</q-form>
</q-card>
</template>
<script>
import mixins from "@/mixins/mixins";
export default {
name: "BulkCommand",
mixins: [mixins],
data() {
return {
target: "client",
shell: "cmd",
timeout: 300,
cmd: null,
tree: null,
client: null,
site: null,
agents: [],
agentMultiple: [],
};
},
computed: {
sites() {
if (this.tree !== null && this.client !== null) {
this.site = this.tree[this.client].sort()[0];
return this.tree[this.client].sort();
}
},
},
methods: {
send() {
this.$q.loading.show();
const data = {
mode: "command",
target: this.target,
client: this.client,
site: this.site,
agentPKs: this.agentMultiple,
cmd: this.cmd,
timeout: this.timeout,
shell: this.shell,
};
this.$axios
.post("/agents/bulk/", data)
.then(r => {
this.$q.loading.hide();
this.$emit("close");
this.notifySuccess(r.data);
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data);
});
},
getTree() {
this.$axios.get("/clients/loadclients/").then(r => {
this.tree = r.data;
this.client = Object.keys(r.data).sort()[0];
});
},
getAgents() {
this.$axios.get("/agents/listagentsnodetail/").then(r => {
const ret = [];
r.data.forEach(i => {
ret.push({ label: i.hostname, value: i.pk });
});
this.agents = Object.freeze(ret.sort((a, b) => a.label.localeCompare(b.label)));
});
},
},
created() {
this.getTree();
this.getAgents();
},
};
</script>

View File

@@ -1,156 +0,0 @@
<template>
<q-card style="min-width: 50vw">
<q-card-section class="row items-center">
<div class="text-h6">Bulk Patch Management</div>
<q-space />
<q-btn icon="close" flat round dense v-close-popup />
</q-card-section>
<q-form @submit.prevent="send">
<q-card-section>
<div class="q-pa-none">
<p>Choose Target</p>
<div class="q-gutter-sm">
<q-radio dense v-model="target" val="client" label="Client" @input="agentMultiple = []" />
<q-radio dense v-model="target" val="site" label="Site" @input="agentMultiple = []" />
<q-radio dense v-model="target" val="agents" label="Selected Agents" />
<q-radio dense v-model="target" val="all" label="All Agents" @input="agentMultiple = []" />
</div>
</div>
</q-card-section>
<q-card-section v-if="tree !== null && client !== null && target === 'client'">
<q-select
dense
:rules="[val => !!val || '*Required']"
outlined
options-dense
label="Select client"
v-model="client"
:options="Object.keys(tree).sort()"
/>
</q-card-section>
<q-card-section v-if="tree !== null && client !== null && target === 'site'">
<q-select
dense
:rules="[val => !!val || '*Required']"
outlined
options-dense
label="Select client"
v-model="client"
:options="Object.keys(tree).sort()"
@input="site = sites[0]"
/>
<q-select
dense
:rules="[val => !!val || '*Required']"
outlined
options-dense
label="Select site"
v-model="site"
:options="sites"
/>
</q-card-section>
<q-card-section v-if="agents.length !== 0 && target === 'agents'">
<q-select
dense
options-dense
filled
v-model="agentMultiple"
multiple
:options="agents"
use-chips
stack-label
map-options
emit-value
label="Select Agents"
/>
</q-card-section>
<q-card-section>
<div class="q-pa-none">
<p>Action</p>
<div class="q-gutter-sm">
<q-radio dense v-model="mode" val="scan" label="Run Patch Status Scan" />
<q-radio dense v-model="mode" val="install" label="Install Pending Patches Now" />
</div>
</div>
</q-card-section>
<q-card-actions align="center">
<q-btn label="Send" color="primary" class="full-width" type="submit" />
</q-card-actions>
</q-form>
</q-card>
</template>
<script>
import mixins from "@/mixins/mixins";
export default {
name: "BulkPatchManagement",
mixins: [mixins],
data() {
return {
target: "client",
tree: null,
client: null,
site: null,
agents: [],
agentMultiple: [],
mode: "scan",
};
},
computed: {
sites() {
if (this.tree !== null && this.client !== null) {
this.site = this.tree[this.client].sort()[0];
return this.tree[this.client].sort();
}
},
},
methods: {
send() {
this.$q.loading.show();
const data = {
mode: this.mode,
target: this.target,
client: this.client,
site: this.site,
agentPKs: this.agentMultiple,
};
this.$axios
.post("/agents/bulk/", data)
.then(r => {
this.$q.loading.hide();
this.$emit("close");
this.notifySuccess(r.data);
})
.catch(e => {
this.$q.loading.hide();
this.notifyError(e.response.data);
});
},
getTree() {
this.$axios.get("/clients/loadclients/").then(r => {
this.tree = r.data;
this.client = Object.keys(r.data).sort()[0];
});
},
getAgents() {
this.$axios.get("/agents/listagentsnodetail/").then(r => {
const ret = [];
r.data.forEach(i => {
ret.push({ label: i.hostname, value: i.pk });
});
this.agents = Object.freeze(ret.sort((a, b) => a.label.localeCompare(b.label)));
});
},
},
created() {
this.getTree();
this.getAgents();
},
};
</script>

View File

@@ -1,77 +0,0 @@
<template>
<q-card style="min-width: 400px">
<q-card-section class="row">
<q-card-actions align="left">
<div class="text-h6">Add Client</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="addClient">
<q-card-section>
<q-input
outlined
v-model="client.client"
label="Client:"
:rules="[val => (val && val.length > 0) || '*Required']"
/>
</q-card-section>
<q-card-section>
<q-input
outlined
v-model="client.site"
label="Default first site:"
:rules="[val => (val && val.length > 0) || '*Required']"
/>
</q-card-section>
<q-card-actions align="right">
<q-btn label="Add Client" color="primary" type="submit" />
<q-btn label="Cancel" v-close-popup />
</q-card-actions>
</q-form>
</q-card-section>
</q-card>
</template>
<script>
import axios from "axios";
import mixins from "@/mixins/mixins";
export default {
name: "AddClient",
mixins: [mixins],
data() {
return {
client: {
client: null,
site: null,
},
};
},
methods: {
addClient() {
this.$q.loading.show();
axios
.post("/clients/clients/", this.client)
.then(r => {
this.$emit("close");
this.$store.dispatch("loadTree");
this.$store.dispatch("getUpdatedSites");
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);
} else {
this.notifyError(e.response.data.non_field_errors);
}
});
},
},
};
</script>

View File

@@ -1,71 +0,0 @@
<template>
<q-card style="min-width: 400px">
<q-card-section class="row">
<q-card-actions align="left">
<div class="text-h6">Add Site</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="addSite">
<q-card-section>
<q-select options-dense emit-value map-options outlined v-model="client" :options="client_options" />
</q-card-section>
<q-card-section>
<q-input
outlined
v-model="siteName"
label="Site Name:"
:rules="[val => (val && val.length > 0) || 'This field is required']"
/>
</q-card-section>
<q-card-actions align="right">
<q-btn label="Add Site" color="primary" type="submit" />
<q-btn label="Cancel" v-close-popup />
</q-card-actions>
</q-form>
</q-card-section>
</q-card>
</template>
<script>
import axios from "axios";
import mixins from "@/mixins/mixins";
export default {
name: "AddSite",
props: ["clients"],
mixins: [mixins],
data() {
return {
client: null,
siteName: "",
};
},
methods: {
addSite() {
axios
.post("/clients/sites/", {
client: this.client,
name: this.siteName,
})
.then(() => {
this.$emit("close");
this.$store.dispatch("loadTree");
this.notifySuccess(`Site ${this.siteName} was added!`);
})
.catch(err => this.notifyError(err.response.data));
},
},
computed: {
client_options() {
return this.clients.map(client => ({ label: client.name, value: client.id }));
},
},
created() {
this.client = this.clients[0].id;
},
};
</script>

View File

@@ -1,88 +0,0 @@
<template>
<q-card style="min-width: 400px">
<q-card-section class="row">
<q-card-actions align="left">
<div class="text-h6">Delete Client</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="deleteClient">
<q-card-section>
<q-select
:rules="[val => !!val || '*Required']"
outlined
options-dense
label="Select client"
v-model="client"
:options="client_options"
emit-value
map-options
/>
</q-card-section>
<q-card-section></q-card-section>
<q-card-actions align="left">
<q-btn :disable="client === null" label="Delete" class="full-width" color="negative" type="submit" />
</q-card-actions>
</q-form>
</q-card-section>
</q-card>
</template>
<script>
import mixins from "@/mixins/mixins";
export default {
name: "DeleteClient",
mixins: [mixins],
props: {
clientpk: Number,
},
data() {
return {
client_options: [],
client: null,
};
},
methods: {
getClients() {
this.$axios.get("/clients/clients/").then(r => {
this.client_options = r.data.map(client => ({ label: client.name, value: client.id }));
});
},
deleteClient() {
this.$q
.dialog({
title: "Are you sure?",
message: "Delete client",
cancel: true,
ok: { label: "Delete", color: "negative" },
})
.onOk(() => {
this.$q.loading.show();
this.$axios
.delete(`/clients/${this.client}/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);
});
});
},
},
created() {
this.getClients();
if (this.clientpk !== undefined && this.clientpk !== null) {
this.client = this.clientpk;
}
},
};
</script>

View File

@@ -1,108 +0,0 @@
<template>
<q-card style="min-width: 400px">
<q-card-section class="row">
<q-card-actions align="left">
<div class="text-h6">Delete Site</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="deleteSite">
<q-card-section>
<q-select
:rules="[val => !!val || '*Required']"
outlined
options-dense
label="Select client"
v-model="client"
:options="client_options"
@input="site = sites[0]"
/>
</q-card-section>
<q-card-section>
<q-select
:rules="[val => !!val || '*Required']"
outlined
options-dense
label="Select site"
v-model="site"
:options="sites"
emit-value
map-options
/>
</q-card-section>
<q-card-actions align="left">
<q-btn :disable="site === null" label="Delete" class="full-width" color="negative" type="submit" />
</q-card-actions>
</q-form>
</q-card-section>
</q-card>
</template>
<script>
import mixins from "@/mixins/mixins";
export default {
name: "DeleteSite",
mixins: [mixins],
props: {
sitepk: Number,
},
data() {
return {
client_options: [],
client: null,
site: null,
};
},
computed: {
sites() {
return !!this.client ? this.client.sites.map(site => ({ label: site.name, value: site.id })) : [];
},
},
methods: {
getClients() {
this.$axios.get("/clients/clients/").then(r => {
this.client_options = this.formatClientOptions(r.data);
if (this.sitepk !== null && this.sitepk !== undefined) {
this.client_options.forEach(client => {
let site = client.sites.find(site => (site.id = this.sitepk));
if (site !== undefined) {
this.site = site.id;
this.client = client;
}
});
} else {
this.client = this.client_options[0];
}
});
},
deleteSite() {
this.$q
.dialog({
title: "Are you sure?",
message: "Delete site",
cancel: true,
ok: { label: "Delete", color: "negative" },
})
.onOk(() => {
this.$axios
.delete(`/clients/${this.site}/site/`)
.then(r => {
this.$emit("edited");
this.$emit("close");
this.notifySuccess(r.data);
})
.catch(e => this.notifyError(e.response.data, 6000));
});
},
},
created() {
this.getClients();
},
};
</script>

View File

@@ -237,8 +237,8 @@ export default function () {
for (let site of client.sites) {
let site_color = "black"
if (site.maintenance_mode) { site_color = "orange" }
else if (site.failing_checks) { site_color = "red" }
if (site.maintenance_mode) { site_color = "warning" }
else if (site.failing_checks) { site_color = "negative" }
childSites.push({
label: site.name,
@@ -251,8 +251,8 @@ export default function () {
}
let client_color = "black"
if (client.maintenance_mode) { client_color = "orange" }
else if (client.failing_checks) { client_color = "red" }
if (client.maintenance_mode) { client_color = "warning" }
else if (client.failing_checks) { client_color = "negative" }
output.push({
label: client.name,