Compare commits

..

5 Commits

Author SHA1 Message Date
wh1te909
f518043d8d Release 0.100.7 2022-08-01 17:36:11 +00:00
wh1te909
cc2335558d Release 0.100.6 2022-07-27 06:15:49 +00:00
wh1te909
a8a171ba2c Release 0.100.5 2022-07-10 00:00:08 +00:00
wh1te909
24a63f477e Release 0.100.4 2022-07-07 16:38:14 +00:00
wh1te909
ddeb6293a1 init 2022-05-17 20:46:22 +00:00
58 changed files with 4740 additions and 4922 deletions

View File

@@ -1,7 +0,0 @@
COMPOSE_PROJECT_NAME=trmm
IMAGE_REPO=tacticalrmm/
VERSION=latest
# DEV SETTINGS
APP_PORT=443
DOCKER_NETWORK=172.21.0.0/24

View File

@@ -1,26 +0,0 @@
version: '3.4'
services:
app-dev:
container_name: trmm-app-dev
image: node:16-alpine
restart: always
command: /bin/sh -c "npm install --cache ~/.npm && npm run serve"
user: 1000:1000
working_dir: /workspace/web
volumes:
- ..:/workspace:cached
ports:
- "8080:443"
networks:
dev:
aliases:
- tactical-frontend
networks:
dev:
driver: bridge
ipam:
driver: default
config:
- subnet: ${DOCKER_NETWORK}

View File

@@ -15,7 +15,7 @@ jobs:
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:
node-version: 18 node-version: 16
- run: touch env-config.js - run: touch env-config.js
@@ -32,3 +32,4 @@ jobs:
uses: softprops/action-gh-release@v1 uses: softprops/action-gh-release@v1
with: with:
files: trmm-web-${{github.ref_name}}.tar.gz files: trmm-web-${{github.ref_name}}.tar.gz

1
.gitignore vendored
View File

@@ -33,4 +33,3 @@ yarn-error.log*
*.sln *.sln
.env .env
/public/env-config.js

View File

@@ -5,7 +5,7 @@
"esbenp.prettier-vscode", "esbenp.prettier-vscode",
"editorconfig.editorconfig", "editorconfig.editorconfig",
"vue.volar", "vue.volar",
"wayou.vscode-todo-highlight" "wayou.vscode-todo-highlight",
], ],
"unwantedRecommendations": [ "unwantedRecommendations": [
"octref.vetur", "octref.vetur",

View File

@@ -4,7 +4,7 @@
"editor.formatOnSave": true, "editor.formatOnSave": true,
"[vue][javascript][typescript][javascriptreact]": { "[vue][javascript][typescript][javascriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode", "editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": ["source.fixAll.eslint"] "editor.codeActionsOnSave": ["source.fixAll.eslint"],
}, },
"eslint.validate": ["javascript", "javascriptreact", "typescript", "vue"], "eslint.validate": ["javascript", "javascriptreact", "typescript", "vue"],
"typescript.tsdk": "node_modules/typescript/lib", "typescript.tsdk": "node_modules/typescript/lib",
@@ -15,7 +15,7 @@
"**/node_modules/": true, "**/node_modules/": true,
"/node_modules/**": true, "/node_modules/**": true,
"**/env/": true, "**/env/": true,
"/env/**": true "/env/**": true,
} }
} }
} }

View File

@@ -1,22 +1,24 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head>
<title><%= productName %></title>
<meta charset="utf-8" /> <head>
<meta name="robots" content="noindex" /> <title>
<meta name="description" content="<%= productDescription %>" /> <%= productName %>
<meta name="format-detection" content="telephone=no" /> </title>
<meta name="msapplication-tap-highlight" content="no" />
<meta <meta charset="utf-8" />
name="viewport" <meta name="robots" content="noindex" />
content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width<% if (ctx.mode.cordova || ctx.mode.capacitor) { %>, viewport-fit=cover<% } %>" <meta name="description" content="<%= productDescription %>" />
/> <meta name="format-detection" content="telephone=no" />
<link rel="icon" type="image/ico" href="favicon.ico" /> <meta name="msapplication-tap-highlight" content="no" />
<script src="/env-config.js"></script> <meta name="viewport"
</head> content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width<% if (ctx.mode.cordova || ctx.mode.capacitor) { %>, viewport-fit=cover<% } %>" />
<link rel="icon" type="image/ico" href="favicon.ico" />
<script src="/env-config.js"></script>
</head>
<body>
<!-- quasar:entry-point -->
</body>
<body>
<!-- quasar:entry-point -->
</body>
</html> </html>

7706
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{ {
"name": "web", "name": "web",
"version": "0.101.23-dev", "version": "0.100.7",
"private": true, "private": true,
"productName": "Tactical RMM", "productName": "Tactical RMM",
"scripts": { "scripts": {
@@ -10,31 +10,31 @@
"format": "prettier --write \"**/*.{js,ts,vue,,html,md,json}\" --ignore-path .gitignore" "format": "prettier --write \"**/*.{js,ts,vue,,html,md,json}\" --ignore-path .gitignore"
}, },
"dependencies": { "dependencies": {
"@quasar/extras": "1.16.4", "@quasar/extras": "1.15.0",
"apexcharts": "3.41.0", "apexcharts": "3.35.4",
"axios": "1.4.0", "axios": "0.27.2",
"dotenv": "16.3.1", "dotenv": "16.0.1",
"qrcode.vue": "3.4.0", "qrcode.vue": "3.3.3",
"quasar": "2.12.1", "quasar": "2.7.5",
"vue": "3.2.47", "vue": "3.2.37",
"vue3-ace-editor": "2.2.2", "vue3-ace-editor": "2.2.2",
"vue3-apexcharts": "1.4.1", "vue3-apexcharts": "1.4.1",
"vuedraggable": "4.1.0", "vuedraggable": "4.1.0",
"vue-router": "4.1.6", "vue-router": "4.1.2",
"vuex": "4.1.0" "vuex": "4.0.2"
}, },
"devDependencies": { "devDependencies": {
"@quasar/cli": "^2.2.1", "@quasar/cli": "^1.3.2",
"@intlify/unplugin-vue-i18n": "^0.10.0", "@intlify/vite-plugin-vue-i18n": "^5.0.1",
"@quasar/app-vite": "^1.4.3", "@quasar/app-vite": "^1.0.5",
"@types/node": "^20.3.2", "@types/node": "^18.6.1",
"@typescript-eslint/eslint-plugin": "^5.60.1", "@typescript-eslint/eslint-plugin": "^5.30.5",
"@typescript-eslint/parser": "^5.60.1", "@typescript-eslint/parser": "^5.30.5",
"autoprefixer": "10.4.14", "autoprefixer": "^10.4.7",
"eslint": "8.43.0", "eslint": "^8.20.0",
"eslint-config-prettier": "8.8.0", "eslint-config-prettier": "^8.5.0",
"eslint-plugin-vue": "8.7.1", "eslint-plugin-vue": "^8.5.0",
"prettier": "2.8.8", "prettier": "^2.7.1",
"typescript": "5.1.6" "typescript": "^4.7.4"
} }
} }

View File

@@ -4,18 +4,18 @@
module.exports = { module.exports = {
plugins: [ plugins: [
// https://github.com/postcss/autoprefixer // https://github.com/postcss/autoprefixer
require("autoprefixer")({ require('autoprefixer')({
overrideBrowserslist: [ overrideBrowserslist: [
"last 4 Chrome versions", 'last 4 Chrome versions',
"last 4 Firefox versions", 'last 4 Firefox versions',
"last 4 Edge versions", 'last 4 Edge versions',
"last 4 Safari versions", 'last 4 Safari versions',
"last 4 Android versions", 'last 4 Android versions',
"last 4 ChromeAndroid versions", 'last 4 ChromeAndroid versions',
"last 4 FirefoxAndroid versions", 'last 4 FirefoxAndroid versions',
"last 4 iOS versions", 'last 4 iOS versions'
], ]
}), })
// https://github.com/elchininet/postcss-rtlcss // https://github.com/elchininet/postcss-rtlcss
// If you want to support RTL css, then // If you want to support RTL css, then
@@ -23,5 +23,5 @@ module.exports = {
// 2. optionally set quasar.config.js > framework > lang to an RTL language // 2. optionally set quasar.config.js > framework > lang to an RTL language
// 3. uncomment the following line: // 3. uncomment the following line:
// require('postcss-rtlcss') // require('postcss-rtlcss')
], ]
}; }

View File

@@ -12,9 +12,6 @@ export default {
body body
overflow-y: hidden overflow-y: hidden
a
color: #1976D2
.tbl-sticky .tbl-sticky
thead tr th thead tr th
position: sticky position: sticky

View File

@@ -12,25 +12,6 @@ export async function fetchUsers(params = {}) {
} }
} }
export async function resetPass(pass) {
const payload = { password: pass };
try {
const { data } = await axios.put(`${baseUrl}/resetpw/`, payload);
return data;
} catch (e) {
console.error(e);
}
}
export async function resetTwoFactor() {
try {
const { data } = await axios.put(`${baseUrl}/reset2fa/`);
return data;
} catch (e) {
console.error(e);
}
}
// role api function // role api function
export async function fetchRoles(params = {}) { export async function fetchRoles(params = {}) {
try { try {

View File

@@ -232,8 +232,3 @@ export async function removeAgentNote(pk) {
const { data } = await axios.delete(`${baseUrl}/notes/${pk}/`); const { data } = await axios.delete(`${baseUrl}/notes/${pk}/`);
return data; return data;
} }
export async function wakeUpWOL(agent_id) {
const { data } = await axios.post(`${baseUrl}/${agent_id}/wol/`);
return data;
}

View File

@@ -38,8 +38,3 @@ export async function runURLAction(payload) {
console.error(e); console.error(e);
} }
} }
export async function generateScript(payload) {
const { data } = await axios.post(`${baseUrl}/openai/generate/`, payload);
return data;
}

View File

@@ -196,14 +196,6 @@
> >
<q-tooltip>Linux</q-tooltip> <q-tooltip>Linux</q-tooltip>
</q-icon> </q-icon>
<q-icon
v-else-if="props.row.plat === 'darwin'"
name="mdi-apple"
size="sm"
color="primary"
>
<q-tooltip>macOS</q-tooltip>
</q-icon>
</q-td> </q-td>
<q-td key="checks-status" :props="props"> <q-td key="checks-status" :props="props">
@@ -211,7 +203,7 @@
v-if="props.row.maintenance_mode" v-if="props.row.maintenance_mode"
name="construction" name="construction"
size="1.2em" size="1.2em"
:color="dash_positive_color" color="green"
> >
<q-tooltip>Maintenance Mode Enabled</q-tooltip> <q-tooltip>Maintenance Mode Enabled</q-tooltip>
</q-icon> </q-icon>
@@ -219,7 +211,7 @@
v-else-if="props.row.checks.failing > 0" v-else-if="props.row.checks.failing > 0"
name="fas fa-check-double" name="fas fa-check-double"
size="1.2em" size="1.2em"
:color="dash_negative_color" color="negative"
> >
<q-tooltip>Checks failing</q-tooltip> <q-tooltip>Checks failing</q-tooltip>
</q-icon> </q-icon>
@@ -227,7 +219,7 @@
v-else-if="props.row.checks.warning > 0" v-else-if="props.row.checks.warning > 0"
name="fas fa-check-double" name="fas fa-check-double"
size="1.2em" size="1.2em"
:color="dash_warning_color" color="warning"
> >
<q-tooltip>Checks warning</q-tooltip> <q-tooltip>Checks warning</q-tooltip>
</q-icon> </q-icon>
@@ -235,7 +227,7 @@
v-else-if="props.row.checks.info > 0" v-else-if="props.row.checks.info > 0"
name="fas fa-check-double" name="fas fa-check-double"
size="1.2em" size="1.2em"
:color="dash_info_color" color="info"
> >
<q-tooltip>Checks info</q-tooltip> <q-tooltip>Checks info</q-tooltip>
</q-icon> </q-icon>
@@ -243,7 +235,7 @@
v-else v-else
name="fas fa-check-double" name="fas fa-check-double"
size="1.2em" size="1.2em"
:color="dash_positive_color" color="positive"
> >
<q-tooltip>Checks passing</q-tooltip> <q-tooltip>Checks passing</q-tooltip>
</q-icon> </q-icon>
@@ -279,7 +271,7 @@
@click="showPendingActionsModal(props.row)" @click="showPendingActionsModal(props.row)"
name="far fa-clock" name="far fa-clock"
size="1.4em" size="1.4em"
:color="dash_warning_color" color="warning"
class="cursor-pointer" class="cursor-pointer"
> >
<q-tooltip <q-tooltip
@@ -303,7 +295,7 @@
v-if="props.row.status === 'overdue'" v-if="props.row.status === 'overdue'"
name="fas fa-signal" name="fas fa-signal"
size="1.2em" size="1.2em"
:color="dash_negative_color" color="negative"
> >
<q-tooltip>Agent overdue</q-tooltip> <q-tooltip>Agent overdue</q-tooltip>
</q-icon> </q-icon>
@@ -311,16 +303,11 @@
v-else-if="props.row.status === 'offline'" v-else-if="props.row.status === 'offline'"
name="fas fa-signal" name="fas fa-signal"
size="1.2em" size="1.2em"
:color="dash_warning_color" color="warning"
> >
<q-tooltip>Agent offline</q-tooltip> <q-tooltip>Agent offline</q-tooltip>
</q-icon> </q-icon>
<q-icon <q-icon v-else name="fas fa-signal" size="1.2em" color="positive">
v-else
name="fas fa-signal"
size="1.2em"
:color="dash_positive_color"
>
<q-tooltip>Agent online</q-tooltip> <q-tooltip>Agent online</q-tooltip>
</q-icon> </q-icon>
</q-td> </q-td>
@@ -369,23 +356,6 @@ export default {
}, },
methods: { methods: {
filterTable(rows, terms, cols, cellValue) { filterTable(rows, terms, cols, cellValue) {
const hiddenFields = [
"version",
"operating_system",
"public_ip",
"cpu_model",
"graphics",
"local_ips",
"make_model",
"physical_disks",
"custom_fields",
"serial_number",
];
// quasar filter only does visible columns so this is a hack to add hidden columns we want to filter
// originally I was modifying cols directly but this led to phantom colum so doing it this way now
// https://github.com/amidaware/tacticalrmm/issues/1264
const allColumns = [...cols, ...hiddenFields.map((field) => ({ field }))];
const lowerTerms = terms ? terms.toLowerCase() : ""; const lowerTerms = terms ? terms.toLowerCase() : "";
let advancedFilter = false; let advancedFilter = false;
let availability = null; let availability = null;
@@ -438,12 +408,8 @@ export default {
} }
// Normal text filter // Normal text filter
return allColumns.some((col) => { return cols.some((col) => {
let valObj = cellValue(col, row); const val = cellValue(col, row) + "";
if (Array.isArray(valObj)) {
valObj = valObj.map((item) => (item.value ? item.value : item));
}
const val = valObj + "";
const haystack = const haystack =
val === "undefined" || val === "null" ? "" : val.toLowerCase(); val === "undefined" || val === "null" ? "" : val.toLowerCase();
return haystack.indexOf(search) !== -1; return haystack.indexOf(search) !== -1;
@@ -494,9 +460,7 @@ export default {
const data = { const data = {
[db_field]: !alert_action, [db_field]: !alert_action,
}; };
const alertColor = !alert_action const alertColor = !alert_action ? "positive" : "info";
? this.dash_positive_color
: this.dash_info_color;
this.$axios.put(`/agents/${agent.agent_id}/`, data).then(() => { this.$axios.put(`/agents/${agent.agent_id}/`, data).then(() => {
this.$q.notify({ this.$q.notify({
color: alertColor, color: alertColor,
@@ -540,13 +504,7 @@ export default {
}, },
}, },
computed: { computed: {
...mapState([ ...mapState(["tableHeight"]),
"tableHeight",
"dash_info_color",
"dash_positive_color",
"dash_negative_color",
"dash_warning_color",
]),
agentDblClickAction() { agentDblClickAction() {
return this.$store.state.agentDblClickAction; return this.$store.state.agentDblClickAction;
}, },

View File

@@ -3,7 +3,7 @@
<q-badge v-if="alertsCount > 0" :color="badgeColor" floating transparent>{{ <q-badge v-if="alertsCount > 0" :color="badgeColor" floating transparent>{{
alertsCountText() alertsCountText()
}}</q-badge> }}</q-badge>
<q-menu :style="{ 'max-height': `${$q.screen.height - 100}px` }"> <q-menu style="max-height: 30vh">
<q-list separator> <q-list separator>
<q-item v-if="alertsCount === 0">No New Alerts</q-item> <q-item v-if="alertsCount === 0">No New Alerts</q-item>
<q-item v-for="alert in topAlerts" :key="alert.id"> <q-item v-for="alert in topAlerts" :key="alert.id">
@@ -59,7 +59,6 @@
</template> </template>
<script> <script>
import { mapState } from "vuex";
import mixins from "@/mixins/mixins"; import mixins from "@/mixins/mixins";
import AlertsOverview from "@/components/modals/alerts/AlertsOverview.vue"; import AlertsOverview from "@/components/modals/alerts/AlertsOverview.vue";
import { getTimeLapse } from "@/utils/format"; import { getTimeLapse } from "@/utils/format";
@@ -76,21 +75,19 @@ export default {
return { return {
alertsCount: 0, alertsCount: 0,
topAlerts: [], topAlerts: [],
errorColor: "red",
warningColor: "orange",
infoColor: "blue",
poll: null, poll: null,
}; };
}, },
computed: { computed: {
...mapState([
"dash_info_color",
"dash_warning_color",
"dash_negative_color",
]),
badgeColor() { badgeColor() {
const severities = this.topAlerts.map((alert) => alert.severity); const severities = this.topAlerts.map((alert) => alert.severity);
if (severities.includes("error")) return this.dash_negative_color; if (severities.includes("error")) return this.errorColor;
else if (severities.includes("warning")) return this.dash_warning_color; else if (severities.includes("warning")) return this.warningColor;
else return this.dash_info_color; else return this.infoColor;
}, },
}, },
methods: { methods: {
@@ -162,9 +159,9 @@ export default {
}); });
}, },
alertIconColor(severity) { alertIconColor(severity) {
if (severity === "error") return this.dash_negative_color; if (severity === "error") return this.errorColor;
else if (severity === "warning") return this.dash_warning_color; else if (severity === "warning") return this.warningColor;
else return this.dash_info_color; else return this.infoColor;
}, },
alertsCountText() { alertsCountText() {
if (this.alertsCount > 99) return "99+"; if (this.alertsCount > 99) return "99+";

View File

@@ -1,75 +0,0 @@
<template>
<q-dialog ref="dialogRef" @hide="onDialogHide">
<q-card class="q-dialog-plugin" style="width: 60vw">
<q-card-section class="row">
<div class="col-3">New password:</div>
<div class="col-9">
<q-input
outlined
dense
v-model="pass"
:type="isPwd ? 'password' : 'text'"
:rules="[(val) => !!val || '*Required']"
>
<template v-slot:append>
<q-icon
:name="isPwd ? 'visibility_off' : 'visibility'"
class="cursor-pointer"
@click="isPwd = !isPwd"
/>
</template>
</q-input>
</div>
<div class="col-3">Confirm password:</div>
<div class="col-9">
<q-input
outlined
dense
v-model="pass2"
:type="isPwd ? 'password' : 'text'"
:rules="[(val) => val === pass || 'Passwords do not match']"
>
<template v-slot:append>
<q-icon
:name="isPwd ? 'visibility_off' : 'visibility'"
class="cursor-pointer"
@click="isPwd = !isPwd"
/>
</template>
</q-input>
</div>
</q-card-section>
<q-card-actions align="right">
<q-btn
color="primary"
label="Reset"
@click="onOKClick"
:disable="!pass || pass !== pass2"
/>
<q-btn color="negative" label="Cancel" @click="onDialogCancel" />
</q-card-actions>
</q-card>
</q-dialog>
</template>
<script setup>
import { ref } from "vue";
import { useDialogPluginComponent } from "quasar";
import { resetPass } from "@/api/accounts";
import { notifySuccess } from "@/utils/notify";
const pass = ref("");
const pass2 = ref("");
const isPwd = ref(true);
defineEmits([...useDialogPluginComponent.emits]);
const { dialogRef, onDialogHide, onDialogOK, onDialogCancel } =
useDialogPluginComponent();
async function onOKClick() {
const ret = await resetPass(pass.value);
notifySuccess(ret);
onDialogOK();
}
</script>

View File

@@ -98,10 +98,6 @@
v-model="localRole.can_reboot_agents" v-model="localRole.can_reboot_agents"
label="Reboot Agents" label="Reboot Agents"
/> />
<q-checkbox
v-model="localRole.can_send_wol"
label="Wake-Up (WoL) Agents"
/>
<q-checkbox <q-checkbox
v-model="localRole.can_install_agents" v-model="localRole.can_install_agents"
label="Install Agents" label="Install Agents"
@@ -441,8 +437,8 @@ export default {
can_run_scripts: false, can_run_scripts: false,
can_run_bulk: false, can_run_bulk: false,
can_manage_winsvcs: false, can_manage_winsvcs: false,
can_recover_agents: false,
can_list_agent_history: false, can_list_agent_history: false,
can_send_wol: false,
// software perms // software perms
can_list_software: false, can_list_software: false,
can_manage_software: false, can_manage_software: false,

View File

@@ -146,13 +146,6 @@
<q-item-section>Run Checks</q-item-section> <q-item-section>Run Checks</q-item-section>
</q-item> </q-item>
<q-item clickable v-close-popup @click="wakeUp(agent)">
<q-item-section side>
<q-icon size="xs" name="offline_bolt" />
</q-item-section>
<q-item-section>Wake-Up (WoL)</q-item-section>
</q-item>
<q-item clickable> <q-item clickable>
<q-item-section side> <q-item-section side>
<q-icon size="xs" name="power_settings_new" /> <q-icon size="xs" name="power_settings_new" />
@@ -217,7 +210,6 @@ import {
removeAgent, removeAgent,
runRemoteBackground, runRemoteBackground,
runTakeControl, runTakeControl,
wakeUpWOL,
} from "@/api/agents"; } from "@/api/agents";
import { runAgentUpdateScan, runAgentUpdateInstall } from "@/api/winupdates"; import { runAgentUpdateScan, runAgentUpdateInstall } from "@/api/winupdates";
import { runAgentChecks } from "@/api/checks"; import { runAgentChecks } from "@/api/checks";
@@ -378,15 +370,6 @@ export default {
} }
} }
async function wakeUp(agent) {
try {
const data = await wakeUpWOL(agent.agent_id);
notifySuccess(data);
} catch (e) {
console.error(e);
}
}
function showRebootLaterModal(agent) { function showRebootLaterModal(agent) {
$q.dialog({ $q.dialog({
component: RebootLater, component: RebootLater,
@@ -515,7 +498,6 @@ export default {
showPolicyAdd, showPolicyAdd,
showAgentRecovery, showAgentRecovery,
pingAgent, pingAgent,
wakeUp,
}; };
}, },
}; };

View File

@@ -261,7 +261,7 @@
<q-td v-else-if="props.row.task_result.status === 'passing'"> <q-td v-else-if="props.row.task_result.status === 'passing'">
<q-icon <q-icon
style="font-size: 1.3rem" style="font-size: 1.3rem"
:color="dash_positive_color" color="positive"
name="check_circle" name="check_circle"
> >
<q-tooltip>Passing</q-tooltip> <q-tooltip>Passing</q-tooltip>
@@ -271,7 +271,7 @@
<q-icon <q-icon
v-if="props.row.alert_severity === 'info'" v-if="props.row.alert_severity === 'info'"
style="font-size: 1.3rem" style="font-size: 1.3rem"
:color="dash_info_color" color="info"
name="info" name="info"
> >
<q-tooltip>Informational</q-tooltip> <q-tooltip>Informational</q-tooltip>
@@ -279,7 +279,7 @@
<q-icon <q-icon
v-else-if="props.row.alert_severity === 'warning'" v-else-if="props.row.alert_severity === 'warning'"
style="font-size: 1.3rem" style="font-size: 1.3rem"
:color="dash_warning_color" color="warning"
name="warning" name="warning"
> >
<q-tooltip>Warning</q-tooltip> <q-tooltip>Warning</q-tooltip>
@@ -287,7 +287,7 @@
<q-icon <q-icon
v-else v-else
style="font-size: 1.3rem" style="font-size: 1.3rem"
:color="dash_negative_color" color="negative"
name="error" name="error"
> >
<q-tooltip>Error</q-tooltip> <q-tooltip>Error</q-tooltip>
@@ -418,10 +418,6 @@ export default {
const tabHeight = computed(() => store.state.tabHeight); const tabHeight = computed(() => store.state.tabHeight);
const agentPlatform = computed(() => store.state.agentPlatform); const agentPlatform = computed(() => store.state.agentPlatform);
const formatDate = computed(() => store.getters.formatDate); const formatDate = computed(() => store.getters.formatDate);
const dash_info_color = computed(() => store.state.dash_info_color);
const dash_positive_color = computed(() => store.state.dash_positive_color);
const dash_negative_color = computed(() => store.state.dash_negative_color);
const dash_warning_color = computed(() => store.state.dash_warning_color);
// setup quasar // setup quasar
const $q = useQuasar(); const $q = useQuasar();
@@ -556,10 +552,6 @@ export default {
selectedAgent, selectedAgent,
tabHeight, tabHeight,
agentPlatform, agentPlatform,
dash_info_color,
dash_positive_color,
dash_warning_color,
dash_negative_color,
// non-reactive data // non-reactive data
columns, columns,

View File

@@ -301,7 +301,7 @@
<q-td v-else-if="props.row.check_result.status === 'passing'"> <q-td v-else-if="props.row.check_result.status === 'passing'">
<q-icon <q-icon
style="font-size: 1.3rem" style="font-size: 1.3rem"
:color="dash_positive_color" color="positive"
name="check_circle" name="check_circle"
> >
<q-tooltip>Passing</q-tooltip> <q-tooltip>Passing</q-tooltip>
@@ -311,7 +311,7 @@
<q-icon <q-icon
v-if="getAlertSeverity(props.row) === 'info'" v-if="getAlertSeverity(props.row) === 'info'"
style="font-size: 1.3rem" style="font-size: 1.3rem"
:color="dash_info_color" color="info"
name="info" name="info"
> >
<q-tooltip>Informational</q-tooltip> <q-tooltip>Informational</q-tooltip>
@@ -319,7 +319,7 @@
<q-icon <q-icon
v-else-if="getAlertSeverity(props.row) === 'warning'" v-else-if="getAlertSeverity(props.row) === 'warning'"
style="font-size: 1.3rem" style="font-size: 1.3rem"
:color="dash_warning_color" color="warning"
name="warning" name="warning"
> >
<q-tooltip>Warning</q-tooltip> <q-tooltip>Warning</q-tooltip>
@@ -327,7 +327,7 @@
<q-icon <q-icon
v-else v-else
style="font-size: 1.3rem" style="font-size: 1.3rem"
:color="dash_negative_color" color="negative"
name="error" name="error"
> >
<q-tooltip>Error</q-tooltip> <q-tooltip>Error</q-tooltip>
@@ -479,10 +479,6 @@ export default {
const tabHeight = computed(() => store.state.tabHeight); const tabHeight = computed(() => store.state.tabHeight);
const agentPlatform = computed(() => store.state.agentPlatform); const agentPlatform = computed(() => store.state.agentPlatform);
const formatDate = computed(() => store.getters.formatDate); const formatDate = computed(() => store.getters.formatDate);
const dash_info_color = computed(() => store.state.dash_info_color);
const dash_positive_color = computed(() => store.state.dash_positive_color);
const dash_negative_color = computed(() => store.state.dash_negative_color);
const dash_warning_color = computed(() => store.state.dash_warning_color);
// setup quasar // setup quasar
const $q = useQuasar(); const $q = useQuasar();
@@ -657,10 +653,6 @@ export default {
tabHeight, tabHeight,
selectedAgent, selectedAgent,
agentPlatform, agentPlatform,
dash_info_color,
dash_positive_color,
dash_warning_color,
dash_negative_color,
// non-reactive data // non-reactive data
columns, columns,

View File

@@ -166,7 +166,7 @@ export default {
type: "textarea", type: "textarea",
isValid: (val) => !!val, isValid: (val) => !!val,
}, },
style: "width: 90vw; max-width: 90vw", style: "width: 30vw; max-width: 50vw;",
ok: { label: "Add" }, ok: { label: "Add" },
cancel: true, cancel: true,
}).onOk(async () => { }).onOk(async () => {
@@ -193,7 +193,7 @@ export default {
type: "textarea", type: "textarea",
isValid: (val) => !!val, isValid: (val) => !!val,
}, },
style: "width: 90vw; max-width: 90vw", style: "width: 30vw; max-width: 50vw;",
ok: { label: "Save" }, ok: { label: "Save" },
cancel: true, cancel: true,
}).onOk(async (data) => { }).onOk(async (data) => {

View File

@@ -18,33 +18,6 @@
icon="refresh" icon="refresh"
@click="refreshSummary" @click="refreshSummary"
/> />
<q-icon
v-if="summary.status === 'overdue'"
name="fas fa-signal"
size="1.2em"
:color="dash_negative_color"
class="q-mr-sm"
>
<q-tooltip>Agent overdue</q-tooltip>
</q-icon>
<q-icon
v-else-if="summary.status === 'offline'"
name="fas fa-signal"
size="1.2em"
:color="dash_warning_color"
class="q-mr-sm"
>
<q-tooltip>Agent offline</q-tooltip>
</q-icon>
<q-icon
v-else
name="fas fa-signal"
size="1.2em"
:color="dash_positive_color"
class="q-mr-sm"
>
<q-tooltip>Agent online</q-tooltip>
</q-icon>
<b>{{ summary.hostname }}</b> <b>{{ summary.hostname }}</b>
<span v-if="summary.maintenance_mode"> <span v-if="summary.maintenance_mode">
&bull; <q-badge color="green"> Maintenance Mode </q-badge> &bull; <q-badge color="green"> Maintenance Mode </q-badge>
@@ -87,7 +60,7 @@
</q-item-section> </q-item-section>
<q-item-section>{{ summary.make_model }}</q-item-section> <q-item-section>{{ summary.make_model }}</q-item-section>
</q-item> </q-item>
<q-item> <q-item v-for="(cpu, i) in summary.cpu_model" :key="cpu + i">
<q-item-section avatar> <q-item-section avatar>
<q-icon name="fas fa-microchip" /> <q-icon name="fas fa-microchip" />
</q-item-section> </q-item-section>
@@ -114,13 +87,6 @@
</q-item-section> </q-item-section>
<q-item-section>{{ summary.graphics }}</q-item-section> <q-item-section>{{ summary.graphics }}</q-item-section>
</q-item> </q-item>
<!-- serial -->
<q-item v-if="serial_number">
<q-item-section avatar>
<q-icon name="fa-solid fa-barcode" />
</q-item-section>
<q-item-section>{{ serial_number }}</q-item-section>
</q-item>
<q-item> <q-item>
<q-item-section avatar> <q-item-section avatar>
<q-icon name="fas fa-globe-americas" /> <q-icon name="fas fa-globe-americas" />
@@ -144,7 +110,7 @@
size="lg" size="lg"
square square
icon="done" icon="done"
:color="dash_positive_color" color="green"
text-color="white" text-color="white"
/> />
<small>{{ summary.checks.passing }} checks passing</small> <small>{{ summary.checks.passing }} checks passing</small>
@@ -154,7 +120,7 @@
size="lg" size="lg"
square square
icon="cancel" icon="cancel"
:color="dash_negative_color" color="red"
text-color="white" text-color="white"
/> />
<small>{{ summary.checks.failing }} checks failing</small> <small>{{ summary.checks.failing }} checks failing</small>
@@ -164,7 +130,7 @@
size="lg" size="lg"
square square
icon="warning" icon="warning"
:color="dash_warning_color" color="warning"
text-color="white" text-color="white"
/> />
<small>{{ summary.checks.warning }} checks warning</small> <small>{{ summary.checks.warning }} checks warning</small>
@@ -174,7 +140,7 @@
size="lg" size="lg"
square square
icon="info" icon="info"
:color="dash_info_color" color="info"
text-color="white" text-color="white"
/> />
<small>{{ summary.checks.info }} checks info</small> <small>{{ summary.checks.info }} checks info</small>
@@ -192,20 +158,6 @@
> >
</div> </div>
<div v-else>No checks</div> <div v-else>No checks</div>
<span
v-if="customFields.length > 0"
class="text-subtitle2 text-bold block q-mt-xl"
>Custom Fields</span
>
<q-list dense>
<q-item v-for="(field, i) in customFields" :key="field + i">
<q-item-section thumbnail>
<q-icon name="fas fa-user" size="xs" />
</q-item-section>
<q-item-section>{{ field.name }}: {{ field.value }}</q-item-section>
</q-item>
</q-list>
</div> </div>
<div class="col-1"></div> <div class="col-1"></div>
<!-- right --> <!-- right -->
@@ -241,7 +193,6 @@ import {
openAgentWindow, openAgentWindow,
} from "@/api/agents"; } from "@/api/agents";
import { notifySuccess } from "@/utils/notify"; import { notifySuccess } from "@/utils/notify";
import { fetchCustomFields } from "@/api/core";
// ui imports // ui imports
import AgentActionMenu from "@/components/agents/AgentActionMenu.vue"; import AgentActionMenu from "@/components/agents/AgentActionMenu.vue";
@@ -256,34 +207,18 @@ export default {
const store = useStore(); const store = useStore();
const selectedAgent = computed(() => store.state.selectedRow); const selectedAgent = computed(() => store.state.selectedRow);
const refreshSummaryTab = computed(() => store.state.refreshSummaryTab); const refreshSummaryTab = computed(() => store.state.refreshSummaryTab);
const dash_info_color = computed(() => store.state.dash_info_color);
const dash_positive_color = computed(() => store.state.dash_positive_color);
const dash_negative_color = computed(() => store.state.dash_negative_color);
const dash_warning_color = computed(() => store.state.dash_warning_color);
// summary tab logic // summary tab logic
const summary = ref(null); const summary = ref(null);
const customFieldsDefinitions = ref(null);
const loading = ref(false); const loading = ref(false);
const serial_number = computed(() => {
return summary.value.wmi_detail.bios?.[0]?.[0]?.SerialNumber;
});
const cpu = computed(() => {
if (summary.value.cpu_model?.length > 1) {
return `${summary.value.cpu_model.length}x ${summary.value.cpu_model[0]}`;
}
return summary.value.cpu_model[0];
});
function diskBarColor(percent) { function diskBarColor(percent) {
if (percent < 80) { if (percent < 80) {
return dash_positive_color.value; return "positive";
} else if (percent > 80 && percent < 95) { } else if (percent > 80 && percent < 95) {
return dash_warning_color.value; return "warning";
} else { } else {
return dash_negative_color.value; return "negative";
} }
} }
@@ -301,37 +236,9 @@ export default {
return ret; return ret;
}); });
const customFields = computed(() => {
if (!summary.value.custom_fields) {
return [];
}
if (!customFieldsDefinitions.value) {
return [];
}
const ret = [];
for (const customField of summary.value.custom_fields) {
const definition = customFieldsDefinitions.value.find(
(def) => def.id === customField.field
);
if (
definition &&
!definition.hide_in_ui &&
customField.value?.length > 0
) {
ret.push({
name: definition.name,
value: customField.value,
});
}
}
return ret;
});
async function getSummary() { async function getSummary() {
loading.value = true; loading.value = true;
summary.value = await fetchAgent(selectedAgent.value); summary.value = await fetchAgent(selectedAgent.value);
customFieldsDefinitions.value = await fetchCustomFields();
store.commit("setRefreshSummaryTab", false); store.commit("setRefreshSummaryTab", false);
store.commit("setAgentPlatform", summary.value.plat); store.commit("setAgentPlatform", summary.value.plat);
loading.value = false; loading.value = false;
@@ -339,7 +246,6 @@ export default {
async function refreshSummary() { async function refreshSummary() {
loading.value = true; loading.value = true;
summary.value = await fetchAgent(selectedAgent.value);
try { try {
const result = await refreshAgentWMI(selectedAgent.value); const result = await refreshAgentWMI(selectedAgent.value);
await getSummary(); await getSummary();
@@ -371,16 +277,9 @@ export default {
return { return {
// reactive data // reactive data
summary, summary,
customFields,
loading, loading,
selectedAgent, selectedAgent,
disks, disks,
dash_info_color,
dash_positive_color,
dash_warning_color,
dash_negative_color,
serial_number,
cpu,
// methods // methods
getSummary, getSummary,

View File

@@ -128,7 +128,7 @@
<q-icon <q-icon
v-else-if="props.row.action === 'ignore'" v-else-if="props.row.action === 'ignore'"
name="fas fa-check" name="fas fa-check"
:color="dash_negative_color" color="negative"
> >
<q-tooltip>Ignore</q-tooltip> <q-tooltip>Ignore</q-tooltip>
</q-icon> </q-icon>
@@ -144,7 +144,7 @@
<q-icon <q-icon
v-if="props.row.installed" v-if="props.row.installed"
name="fas fa-check" name="fas fa-check"
:color="dash_positive_color" color="positive"
> >
<q-tooltip>Installed</q-tooltip> <q-tooltip>Installed</q-tooltip>
</q-icon> </q-icon>
@@ -158,15 +158,11 @@
<q-icon <q-icon
v-else-if="props.row.action == 'ignore'" v-else-if="props.row.action == 'ignore'"
name="fas fa-ban" name="fas fa-ban"
:color="dash_negative_color" color="negative"
> >
<q-tooltip>Ignored</q-tooltip> <q-tooltip>Ignored</q-tooltip>
</q-icon> </q-icon>
<q-icon <q-icon v-else name="fas fa-exclamation" color="warning">
v-else
name="fas fa-exclamation"
:color="dash_warning_color"
>
<q-tooltip>Missing</q-tooltip> <q-tooltip>Missing</q-tooltip>
</q-icon> </q-icon>
</q-td> </q-td>
@@ -255,9 +251,6 @@ export default {
const tabHeight = computed(() => store.state.tabHeight); const tabHeight = computed(() => store.state.tabHeight);
const agentPlatform = computed(() => store.state.agentPlatform); const agentPlatform = computed(() => store.state.agentPlatform);
const formatDate = computed(() => store.getters.formatDate); const formatDate = computed(() => store.getters.formatDate);
const dash_positive_color = computed(() => store.state.dash_positive_color);
const dash_negative_color = computed(() => store.state.dash_negative_color);
const dash_warning_color = computed(() => store.state.dash_warning_color);
// setup quasar // setup quasar
const $q = useQuasar(); const $q = useQuasar();
@@ -317,10 +310,9 @@ export default {
} }
function showUpdateDetails(update) { function showUpdateDetails(update) {
const color = $q.dark.isActive ? "white" : "";
let support_urls = ""; let support_urls = "";
update.more_info_urls.forEach((u) => { update.more_info_urls.forEach((u) => {
support_urls += `<a style='color: ${color}' href='${u}' target='_blank'>${u}</a><br/>`; support_urls += `<a href='${u}' target='_blank'>${u}</a><br/>`;
}); });
let cats = update.categories.join(", "); let cats = update.categories.join(", ");
$q.dialog({ $q.dialog({
@@ -355,9 +347,6 @@ export default {
selectedAgent, selectedAgent,
tabHeight, tabHeight,
agentPlatform, agentPlatform,
dash_positive_color,
dash_warning_color,
dash_negative_color,
// non-reactive data // non-reactive data
columns, columns,

View File

@@ -7,17 +7,6 @@
<q-badge color="primary" class="q-ml-sm text-caption">{{ <q-badge color="primary" class="q-ml-sm text-caption">{{
v v
}}</q-badge> }}</q-badge>
<q-btn
v-if="!!v"
size="sm"
class="q-ml-xs"
flat
round
icon="content_copy"
@click="copyValueToClip(v)"
>
<q-tooltip>Copy to Clipboard</q-tooltip>
</q-btn>
</div> </div>
</div> </div>
<q-separator v-if="info.length > 1" /> <q-separator v-if="info.length > 1" />
@@ -26,8 +15,6 @@
</template> </template>
<script> <script>
import { copyToClipboard } from "quasar";
import { notifySuccess } from "@/utils/notify";
// composition imports // composition imports
import { computed } from "vue"; import { computed } from "vue";
import { useStore } from "vuex"; import { useStore } from "vuex";
@@ -41,16 +28,9 @@ export default {
const store = useStore(); const store = useStore();
const tabHeight = computed(() => store.state.tabHeight); const tabHeight = computed(() => store.state.tabHeight);
function copyValueToClip(val) {
copyToClipboard(val).then(() => {
notifySuccess("Copied to clipboard");
});
}
return { return {
tabHeight, tabHeight,
uid, uid,
copyValueToClip,
}; };
}, },
}; };

View File

@@ -217,7 +217,6 @@
</template> </template>
<script> <script>
import { mapState } from "vuex";
import mixins from "@/mixins/mixins"; import mixins from "@/mixins/mixins";
import PolicyStatus from "@/components/automation/modals/PolicyStatus.vue"; import PolicyStatus from "@/components/automation/modals/PolicyStatus.vue";
import DiskSpaceCheck from "@/components/checks/DiskSpaceCheck.vue"; import DiskSpaceCheck from "@/components/checks/DiskSpaceCheck.vue";
@@ -269,9 +268,6 @@ export default {
if (newValue !== oldValue) this.getChecks(); if (newValue !== oldValue) this.getChecks();
}, },
}, },
computed: {
...mapState(["dash_positive_color", "dash_warning_color"]),
},
methods: { methods: {
getChecks() { getChecks() {
this.$q.loading.show(); this.$q.loading.show();
@@ -299,9 +295,7 @@ export default {
data.check_alert = true; data.check_alert = true;
const act = !action ? "enabled" : "disabled"; const act = !action ? "enabled" : "disabled";
const color = !action const color = !action ? "positive" : "warning";
? this.dash_positive_color
: this.dash_warning_color;
this.$axios this.$axios
.put(`/checks/${id}/`, data) .put(`/checks/${id}/`, data)
.then(() => { .then(() => {

View File

@@ -41,7 +41,7 @@
<q-td v-if="props.row.status === 'passing'"> <q-td v-if="props.row.status === 'passing'">
<q-icon <q-icon
style="font-size: 1.3rem" style="font-size: 1.3rem"
:color="dash_positive_color" color="positive"
name="check_circle" name="check_circle"
> >
<q-tooltip>Passing</q-tooltip> <q-tooltip>Passing</q-tooltip>
@@ -51,7 +51,7 @@
<q-icon <q-icon
v-if="props.row.alert_severity === 'info'" v-if="props.row.alert_severity === 'info'"
style="font-size: 1.3rem" style="font-size: 1.3rem"
:color="dash_info_color" color="info"
name="info" name="info"
> >
<q-tooltip>Informational</q-tooltip> <q-tooltip>Informational</q-tooltip>
@@ -59,7 +59,7 @@
<q-icon <q-icon
v-else-if="props.row.alert_severity === 'warning'" v-else-if="props.row.alert_severity === 'warning'"
style="font-size: 1.3rem" style="font-size: 1.3rem"
:color="dash_warning_color" color="warning"
name="warning" name="warning"
> >
<q-tooltip>Warning</q-tooltip> <q-tooltip>Warning</q-tooltip>
@@ -67,7 +67,7 @@
<q-icon <q-icon
v-else v-else
style="font-size: 1.3rem" style="font-size: 1.3rem"
:color="dash_negative_color" color="negative"
name="error" name="error"
> >
<q-tooltip>Error</q-tooltip> <q-tooltip>Error</q-tooltip>
@@ -148,7 +148,7 @@
<script> <script>
import { computed } from "vue"; import { computed } from "vue";
import { useStore, mapState } from "vuex"; import { useStore } from "vuex";
import ScriptOutput from "@/components/checks/ScriptOutput.vue"; import ScriptOutput from "@/components/checks/ScriptOutput.vue";
import EventLogCheckOutput from "@/components/checks/EventLogCheckOutput.vue"; import EventLogCheckOutput from "@/components/checks/EventLogCheckOutput.vue";
@@ -220,12 +220,6 @@ export default {
}; };
}, },
computed: { computed: {
...mapState([
"dash_info_color",
"dash_positive_color",
"dash_negative_color",
"dash_warning_color",
]),
title() { title() {
return !!this.item.readable_desc return !!this.item.readable_desc
? this.item.readable_desc + " Status" ? this.item.readable_desc + " Status"

View File

@@ -39,19 +39,6 @@
new-value-mode="add" new-value-mode="add"
/> />
</q-card-section> </q-card-section>
<q-card-section>
<q-select
dense
:label="envVarsLabel"
filled
v-model="state.env_vars"
use-input
use-chips
multiple
hide-dropdown-icon
new-value-mode="add"
/>
</q-card-section>
<q-card-section> <q-card-section>
<tactical-dropdown <tactical-dropdown
label="Informational return codes (press Enter after typing each code)" label="Informational return codes (press Enter after typing each code)"
@@ -128,7 +115,6 @@ import { useDialogPluginComponent } from "quasar";
import { useCheckModal } from "@/composables/checks"; import { useCheckModal } from "@/composables/checks";
import { useScriptDropdown } from "@/composables/scripts"; import { useScriptDropdown } from "@/composables/scripts";
import { validateRetcode } from "@/utils/validation"; import { validateRetcode } from "@/utils/validation";
import { envVarsLabel } from "@/constants/constants";
// ui imports // ui imports
import TacticalDropdown from "@/components/ui/TacticalDropdown.vue"; import TacticalDropdown from "@/components/ui/TacticalDropdown.vue";
@@ -146,15 +132,10 @@ export default {
const { dialogRef, onDialogHide, onDialogOK } = useDialogPluginComponent(); const { dialogRef, onDialogHide, onDialogOK } = useDialogPluginComponent();
// setup script dropdown // setup script dropdown
const { const { script, scriptOptions, defaultTimeout, defaultArgs } =
script, useScriptDropdown(props.check ? props.check.script : undefined, {
scriptOptions, onMount: true,
defaultTimeout, });
defaultArgs,
defaultEnvVars,
} = useScriptDropdown(props.check ? props.check.script : undefined, {
onMount: true,
});
// check logic // check logic
const { state, loading, submit, failOptions, severityOptions } = const { state, loading, submit, failOptions, severityOptions } =
@@ -164,7 +145,6 @@ export default {
...props.parent, ...props.parent,
script, script,
script_args: defaultArgs, script_args: defaultArgs,
env_vars: defaultEnvVars,
timeout: defaultTimeout, timeout: defaultTimeout,
check_type: "script", check_type: "script",
fails_b4_alert: 1, fails_b4_alert: 1,
@@ -183,7 +163,6 @@ export default {
failOptions, failOptions,
scriptOptions, scriptOptions,
severityOptions, severityOptions,
envVarsLabel,
// methods // methods
submit, submit,

View File

@@ -122,7 +122,7 @@ export default {
try { try {
const result = props.APIKey const result = props.APIKey
? await editAPIKey(data.id, data) ? await editAPIKey(data)
: await saveAPIKey(data); : await saveAPIKey(data);
onDialogOK(); onDialogOK();
notifySuccess(result); notifySuccess(result);

View File

@@ -208,7 +208,7 @@ export default {
} }
// component lifecycle hooks // component lifecycle hooks
onMounted(getAPIKeys); onMounted(getAPIKeys());
return { return {
// reactive data // reactive data
keys, keys,

View File

@@ -304,9 +304,6 @@ export default {
// setup vuex // setup vuex
const store = useStore(); const store = useStore();
const formatDate = computed(() => store.getters.formatDate); const formatDate = computed(() => store.getters.formatDate);
const dash_positive_color = computed(() => store.state.dash_positive_color);
const dash_negative_color = computed(() => store.state.dash_negative_color);
const dash_warning_color = computed(() => store.state.dash_warning_color);
// setup dropdowns // setup dropdowns
const { clientOptions, getClientOptions } = useClientDropdown(); const { clientOptions, getClientOptions } = useClientDropdown();
@@ -384,18 +381,12 @@ export default {
} }
function formatActionColor(action) { function formatActionColor(action) {
switch (action.toLowerCase()) { if (action === "add") return "success";
case "modify": else if (action === "agent_install") return "success";
return dash_warning_color.value; else if (action === "modify") return "warning";
case "add": else if (action === "delete") return "negative";
case "agent_install": else if (action === "failed_login") return "negative";
return dash_positive_color.value; else return "primary";
case "delete":
case "failed_login":
return dash_negative_color.value;
default:
return "primary";
}
} }
// watchers // watchers

View File

@@ -68,25 +68,25 @@
/> />
<q-radio <q-radio
v-model="logLevelFilter" v-model="logLevelFilter"
:color="dash_info_color" color="cyan"
val="info" val="info"
label="Info" label="Info"
/> />
<q-radio <q-radio
v-model="logLevelFilter" v-model="logLevelFilter"
:color="dash_negative_color" color="red"
val="critical" val="critical"
label="Critical" label="Critical"
/> />
<q-radio <q-radio
v-model="logLevelFilter" v-model="logLevelFilter"
:color="dash_negative_color" color="red"
val="error" val="error"
label="Error" label="Error"
/> />
<q-radio <q-radio
v-model="logLevelFilter" v-model="logLevelFilter"
:color="dash_warning_color" color="yellow"
val="warning" val="warning"
label="Warning" label="Warning"
/> />
@@ -109,7 +109,7 @@
<template v-slot:top-row> <template v-slot:top-row>
<q-tr v-if="Array.isArray(debugLog) && debugLog.length === 1000"> <q-tr v-if="Array.isArray(debugLog) && debugLog.length === 1000">
<q-td colspan="100%"> <q-td colspan="100%">
<q-icon name="warning" :color="dash_warning_color" /> <q-icon name="warning" color="warning" />
Results are limited to 1000 rows. Results are limited to 1000 rows.
</q-td> </q-td>
</q-tr> </q-tr>
@@ -203,10 +203,6 @@ export default {
const store = useStore(); const store = useStore();
const formatDate = computed(() => store.getters.formatDate); const formatDate = computed(() => store.getters.formatDate);
const dash_info_color = computed(() => store.state.dash_info_color);
const dash_positive_color = computed(() => store.state.dash_positive_color);
const dash_negative_color = computed(() => store.state.dash_negative_color);
const dash_warning_color = computed(() => store.state.dash_warning_color);
// setup dropdowns // setup dropdowns
const { agentOptions, getAgentOptions } = useAgentDropdown(); const { agentOptions, getAgentOptions } = useAgentDropdown();
@@ -265,10 +261,6 @@ export default {
agentOptions, agentOptions,
loading, loading,
filter, filter,
dash_info_color,
dash_positive_color,
dash_warning_color,
dash_negative_color,
// non-reactive data // non-reactive data
columns, columns,

View File

@@ -10,13 +10,10 @@
</q-card-actions> </q-card-actions>
</q-card-section> </q-card-section>
<q-card-section> <q-card-section>
<p v-if="info.plat === 'windows'" class="text-subtitle1"> <p class="text-subtitle1">
Download the agent then run the following command from an elevated Download the agent then run the following command from an elevated
command prompt on the device you want to add. command prompt on the device you want to add.
</p> </p>
<p v-else-if="info.plat === 'darwin'" class="text-subtitle1">
Run the following command from a terminal
</p>
<p> <p>
<q-field outlined :color="$q.dark.isActive ? 'white' : 'black'"> <q-field outlined :color="$q.dark.isActive ? 'white' : 'black'">
<code>{{ info.data.cmd }}</code> <code>{{ info.data.cmd }}</code>
@@ -40,7 +37,7 @@
</q-badge> </q-badge>
<span>Do not popup any message boxes during install</span> <span>Do not popup any message boxes during install</span>
</div> </div>
<div v-if="info.plat === 'windows'" class="q-pa-xs q-gutter-xs"> <div class="q-pa-xs q-gutter-xs">
<q-badge class="text-caption q-mr-xs" color="grey" text-color="black"> <q-badge class="text-caption q-mr-xs" color="grey" text-color="black">
<code <code
>-local-mesh "C:\\&lt;some folder or >-local-mesh "C:\\&lt;some folder or
@@ -49,7 +46,7 @@
</q-badge> </q-badge>
<span> To skip downloading the Mesh Agent during the install.</span> <span> To skip downloading the Mesh Agent during the install.</span>
</div> </div>
<div v-if="info.plat === 'windows'" class="q-pa-xs q-gutter-xs"> <div class="q-pa-xs q-gutter-xs">
<q-badge class="text-caption q-mr-xs" color="grey" text-color="black"> <q-badge class="text-caption q-mr-xs" color="grey" text-color="black">
<code <code
>-meshdir "C:\Program Files\Your Company Name\Mesh Agent"</code >-meshdir "C:\Program Files\Your Company Name\Mesh Agent"</code
@@ -66,7 +63,7 @@
</q-badge> </q-badge>
<span>Don't install the mesh agent</span> <span>Don't install the mesh agent</span>
</div> </div>
<div v-if="info.plat === 'windows'" class="q-pa-xs q-gutter-xs"> <div class="q-pa-xs q-gutter-xs">
<q-badge class="text-caption q-mr-xs" color="grey" text-color="black"> <q-badge class="text-caption q-mr-xs" color="grey" text-color="black">
<code>-cert "C:\\&lt;some folder or path&gt;\\ca.pem"</code> <code>-cert "C:\\&lt;some folder or path&gt;\\ca.pem"</code>
</q-badge> </q-badge>
@@ -90,12 +87,11 @@
Note: the auth token above will be valid for {{ info.expires }} hours. Note: the auth token above will be valid for {{ info.expires }} hours.
</p> </p>
<q-btn <q-btn
v-if="info.plat === 'windows'"
type="a" type="a"
:href="info.data.url" :href="info.data.url"
color="primary" color="primary"
label="Download Agent" label="Download Agent"
></q-btn> />
</q-card-section> </q-card-section>
</q-card> </q-card>
</template> </template>

View File

@@ -102,18 +102,6 @@
new-value-mode="add" new-value-mode="add"
/> />
</q-card-section> </q-card-section>
<q-card-section v-if="mode === 'script'" class="q-pt-none">
<tactical-dropdown
v-model="state.env_vars"
:label="envVarsLabel"
filled
use-input
multiple
hide-dropdown-icon
input-debounce="0"
new-value-mode="add"
/>
</q-card-section>
<q-card-section v-if="mode === 'command'"> <q-card-section v-if="mode === 'command'">
<p>Shell</p> <p>Shell</p>
@@ -220,7 +208,7 @@ import { runBulkAction } from "@/api/agents";
import { notifySuccess } from "@/utils/notify"; import { notifySuccess } from "@/utils/notify";
import { cmdPlaceholder } from "@/composables/agents"; import { cmdPlaceholder } from "@/composables/agents";
import { removeExtraOptionCategories } from "@/utils/format"; import { removeExtraOptionCategories } from "@/utils/format";
import { envVarsLabel, runAsUserToolTip } from "@/constants/constants"; import { runAsUserToolTip } from "@/constants/constants";
// ui imports // ui imports
import TacticalDropdown from "@/components/ui/TacticalDropdown.vue"; import TacticalDropdown from "@/components/ui/TacticalDropdown.vue";
@@ -235,7 +223,6 @@ const monTypeOptions = [
const osTypeOptions = [ const osTypeOptions = [
{ label: "Windows", value: "windows" }, { label: "Windows", value: "windows" },
{ label: "Linux", value: "linux" }, { label: "Linux", value: "linux" },
{ label: "macOS", value: "darwin" },
{ label: "All", value: "all" }, { label: "All", value: "all" },
]; ];
@@ -296,7 +283,6 @@ export default {
scriptOptions, scriptOptions,
defaultTimeout, defaultTimeout,
defaultArgs, defaultArgs,
defaultEnvVars,
getScriptOptions, getScriptOptions,
} = useScriptDropdown(); } = useScriptDropdown();
const { agents, agentOptions, getAgentOptions } = useAgentDropdown(); const { agents, agentOptions, getAgentOptions } = useAgentDropdown();
@@ -320,7 +306,6 @@ export default {
script, script,
timeout: defaultTimeout, timeout: defaultTimeout,
args: defaultArgs, args: defaultArgs,
env_vars: defaultEnvVars,
run_as_user: false, run_as_user: false,
}); });
const loading = ref(false); const loading = ref(false);
@@ -418,7 +403,6 @@ export default {
targetOptions, targetOptions,
patchModeOptions, patchModeOptions,
runAsUserToolTip, runAsUserToolTip,
envVarsLabel,
//computed //computed
modalTitle, modalTitle,

View File

@@ -94,7 +94,7 @@
class="q-pr-sm" class="q-pr-sm"
name="fas fa-signal" name="fas fa-signal"
size="1.2em" size="1.2em"
:color="dash_warning_color" color="warning"
/> />
Mark an agent as Mark an agent as
<span class="text-weight-bold">offline</span> if it has <span class="text-weight-bold">offline</span> if it has
@@ -120,7 +120,7 @@
class="q-pr-sm" class="q-pr-sm"
name="fas fa-signal" name="fas fa-signal"
size="1.2em" size="1.2em"
:color="dash_negative_color" color="negative"
/> />
Mark an agent as Mark an agent as
<span class="text-weight-bold">overdue</span> if it has <span class="text-weight-bold">overdue</span> if it has
@@ -373,7 +373,6 @@
</template> </template>
<script> <script>
import { mapState } from "vuex";
import { useDialogPluginComponent } from "quasar"; import { useDialogPluginComponent } from "quasar";
import mixins from "@/mixins/mixins"; import mixins from "@/mixins/mixins";
import PatchPolicyForm from "@/components/modals/agents/PatchPolicyForm.vue"; import PatchPolicyForm from "@/components/modals/agents/PatchPolicyForm.vue";
@@ -466,51 +465,8 @@ export default {
}); });
}, },
editAgent() { editAgent() {
// TODO we need to fix the serializer to not send this stuff delete this.agent.all_timezones;
const toRemove = [ delete this.agent.timezone;
"created_by",
"created_time",
"modified_by",
"modified_time",
"all_timezones",
"timezone",
"wmi_detail",
"services",
"status",
"cpu_model",
"local_ips",
"make_model",
"physical_disks",
"graphics",
"checks",
"patches_last_installed",
"last_seen",
"applied_policies",
"effective_patch_policy",
"version",
"operating_system",
"plat",
"goarch",
"hostname",
"public_ip",
"total_ram",
"disks",
"boot_time",
"logged_in_username",
"last_logged_in_user",
"needs_reboot",
"choco_installed",
"policy",
"mesh_node_id",
"block_policy_inheritance",
"maintenance_mode",
"alert_template",
"client",
"site_name",
];
for (const elem of toRemove) {
delete this.agent[elem];
}
// only send the timezone data if it has changed // only send the timezone data if it has changed
// this way django will keep the db column as null and inherit from the global setting // this way django will keep the db column as null and inherit from the global setting
@@ -547,12 +503,9 @@ export default {
else if (day === 0) result += "Sun, "; else if (day === 0) result += "Sun, ";
} }
return result.trimEnd(","); return result.trimRight(",");
}, },
}, },
computed: {
...mapState(["dash_warning_color", "dash_negative_color"]),
},
mounted() { mounted() {
// Get custom fields // Get custom fields
this.getCustomFields("agent").then((r) => { this.getCustomFields("agent").then((r) => {

View File

@@ -52,15 +52,6 @@
goarch = GOARCH_AMD64; goarch = GOARCH_AMD64;
" "
/> />
<q-radio
v-model="agentOS"
val="darwin"
label="macOS"
@update:model-value="
installMethod = 'mac';
goarch = GOARCH_AMD64;
"
/>
</div> </div>
</q-card-section> </q-card-section>
<q-card-section> <q-card-section>
@@ -114,37 +105,37 @@
v-model="goarch" v-model="goarch"
:val="GOARCH_AMD64" :val="GOARCH_AMD64"
label="64 bit" label="64 bit"
v-show="agentOS === 'windows' || agentOS === 'linux'" v-show="agentOS === 'windows'"
/>
<q-radio
v-model="goarch"
:val="GOARCH_AMD64"
label="Intel 64 bit"
v-show="agentOS === 'darwin'"
/> />
<q-radio <q-radio
v-model="goarch" v-model="goarch"
:val="GOARCH_i386" :val="GOARCH_i386"
label="32 bit" label="32 bit"
v-show="agentOS !== 'darwin'" v-show="agentOS === 'windows'"
/>
<q-radio
v-model="goarch"
:val="GOARCH_AMD64"
label="64 bit"
v-show="agentOS !== 'windows'"
/>
<q-radio
v-model="goarch"
:val="GOARCH_i386"
label="32 bit"
v-show="agentOS !== 'windows'"
/> />
<q-radio <q-radio
v-model="goarch" v-model="goarch"
:val="GOARCH_ARM64" :val="GOARCH_ARM64"
label="ARM 64 bit" label="ARM 64 bit"
v-show="agentOS === 'linux'" v-show="agentOS !== 'windows'"
/>
<q-radio
v-model="goarch"
:val="GOARCH_ARM64"
label="Apple Silicon (M1, M2)"
v-show="agentOS === 'darwin'"
/> />
<q-radio <q-radio
v-model="goarch" v-model="goarch"
:val="GOARCH_ARM32" :val="GOARCH_ARM32"
label="ARM 32 bit (Rasp Pi)" label="ARM 32 bit (Rasp Pi)"
v-show="agentOS === 'linux'" v-show="agentOS !== 'windows'"
/> />
</div> </div>
</q-card-section> </q-card-section>
@@ -275,13 +266,12 @@ export default {
plat: this.agentOS, plat: this.agentOS,
}; };
if (this.installMethod === "manual" || this.installMethod === "mac") { if (this.installMethod === "manual") {
this.$axios.post("/agents/installer/", data).then((r) => { this.$axios.post("/agents/installer/", data).then((r) => {
this.info = { this.info = {
expires: this.expires, expires: this.expires,
data: r.data, data: r.data,
goarch: this.goarch, goarch: this.goarch,
plat: this.agentOS,
}; };
this.showAgentDownload = true; this.showAgentDownload = true;
}); });
@@ -353,9 +343,6 @@ export default {
case "bash": case "bash":
text = "Download linux install script"; text = "Download linux install script";
break; break;
case "mac":
text = "Show installation instructions";
break;
} }
return text; return text;

View File

@@ -77,18 +77,6 @@
new-value-mode="add" new-value-mode="add"
/> />
</q-card-section> </q-card-section>
<q-card-section>
<tactical-dropdown
v-model="state.env_vars"
:label="envVarsLabel"
filled
use-input
multiple
hide-dropdown-icon
input-debounce="0"
new-value-mode="add"
/>
</q-card-section>
<q-card-section> <q-card-section>
<q-option-group <q-option-group
v-model="state.output" v-model="state.output"
@@ -190,7 +178,7 @@ import { useScriptDropdown } from "@/composables/scripts";
import { useCustomFieldDropdown } from "@/composables/core"; import { useCustomFieldDropdown } from "@/composables/core";
import { runScript } from "@/api/agents"; import { runScript } from "@/api/agents";
import { notifySuccess } from "@/utils/notify"; import { notifySuccess } from "@/utils/notify";
import { envVarsLabel, runAsUserToolTip } from "@/constants/constants"; import { runAsUserToolTip } from "@/constants/constants";
import { import {
formatScriptSyntax, formatScriptSyntax,
removeExtraOptionCategories, removeExtraOptionCategories,
@@ -221,18 +209,11 @@ export default {
const { dialogRef, onDialogHide } = useDialogPluginComponent(); const { dialogRef, onDialogHide } = useDialogPluginComponent();
// setup dropdowns // setup dropdowns
const { const { script, scriptOptions, defaultTimeout, defaultArgs, syntax, link } =
script, useScriptDropdown(props.script, {
scriptOptions, onMount: true,
defaultTimeout, filterByPlatform: props.agent.plat,
defaultArgs, });
defaultEnvVars,
syntax,
link,
} = useScriptDropdown(props.script, {
onMount: true,
filterByPlatform: props.agent.plat,
});
const { customFieldOptions } = useCustomFieldDropdown({ onMount: true }); const { customFieldOptions } = useCustomFieldDropdown({ onMount: true });
// main run script functionaity // main run script functionaity
@@ -244,7 +225,6 @@ export default {
save_all_output: false, save_all_output: false,
script, script,
args: defaultArgs, args: defaultArgs,
env_vars: defaultEnvVars,
timeout: defaultTimeout, timeout: defaultTimeout,
run_as_user: false, run_as_user: false,
}); });
@@ -301,7 +281,6 @@ export default {
// non-reactive data // non-reactive data
outputOptions, outputOptions,
runAsUserToolTip, runAsUserToolTip,
envVarsLabel,
//methods //methods
formatScriptSyntax, formatScriptSyntax,

View File

@@ -204,20 +204,6 @@
new-value-mode="add" new-value-mode="add"
/> />
<q-select
class="q-mb-sm"
dense
label="Failure action environment vars (press Enter after typing each key=value pair)"
filled
v-model="template.action_env_vars"
use-input
use-chips
multiple
hide-dropdown-icon
input-debounce="0"
new-value-mode="add"
/>
<q-input <q-input
class="q-mb-sm" class="q-mb-sm"
label="Failure action timeout (seconds)" label="Failure action timeout (seconds)"
@@ -291,20 +277,6 @@
new-value-mode="add" new-value-mode="add"
/> />
<q-select
class="q-mb-sm"
dense
label="Resolved action environment vars (press Enter after typing each key=value pair)"
filled
v-model="template.resolved_action_env_vars"
use-input
use-chips
multiple
hide-dropdown-icon
input-debounce="0"
new-value-mode="add"
/>
<q-input <q-input
class="q-mb-sm" class="q-mb-sm"
label="Resolved action timeout (seconds)" label="Resolved action timeout (seconds)"
@@ -724,11 +696,9 @@ export default {
is_active: true, is_active: true,
action: null, action: null,
action_args: [], action_args: [],
action_env_vars: [],
action_timeout: 15, action_timeout: 15,
resolved_action: null, resolved_action: null,
resolved_action_args: [], resolved_action_args: [],
resolved_action_env_vars: [],
resolved_action_timeout: 15, resolved_action_timeout: 15,
email_recipients: [], email_recipients: [],
email_from: "", email_from: "",
@@ -792,13 +762,11 @@ export default {
(i) => i.value === this.template.action (i) => i.value === this.template.action
); );
this.template.action_args = script.args; this.template.action_args = script.args;
this.template.action_env_vars = script.env_vars;
} else if (type === "resolved") { } else if (type === "resolved") {
const script = this.scriptOptions.find( const script = this.scriptOptions.find(
(i) => i.value === this.template.resolved_action (i) => i.value === this.template.resolved_action
); );
this.template.resolved_action_args = script.args; this.template.resolved_action_args = script.args;
this.template.resolved_action_env_vars = script.env_vars;
} }
}, },
toggleAddEmail() { toggleAddEmail() {

View File

@@ -12,7 +12,6 @@
<q-tab name="urlactions" label="URL Actions" /> <q-tab name="urlactions" label="URL Actions" />
<q-tab name="retention" label="Retention" /> <q-tab name="retention" label="Retention" />
<q-tab name="apikeys" label="API Keys" /> <q-tab name="apikeys" label="API Keys" />
<!-- <q-tab name="openai" label="Open AI" /> -->
</q-tabs> </q-tabs>
</template> </template>
<template v-slot:after> <template v-slot:after>
@@ -509,49 +508,6 @@
<q-tab-panel name="apikeys"> <q-tab-panel name="apikeys">
<APIKeysTable /> <APIKeysTable />
</q-tab-panel> </q-tab-panel>
<!-- Open AI -->
<!-- <q-tab-panel name="openai">
<div class="text-subtitle2">Open AI</div>
<q-separator />
<q-card-section class="row">
<div class="col-4">API Key:</div>
<div class="col-2"></div>
<q-input
dense
outlined
v-model="settings.open_ai_token"
class="col-6"
/>
</q-card-section>
<q-card-section class="row">
<div class="col-4">Open AI Model:</div>
<div class="col-2"></div>
<q-input
dense
outlined
v-model="settings.open_ai_model"
class="col-6"
>
<template v-slot:after>
<q-btn
round
dense
flat
icon="info"
size="sm"
@click="
openURL(
'https://platform.openai.com/docs/models/overview'
)
"
>
<q-tooltip>Click to see available options</q-tooltip>
</q-btn>
</template>
</q-input>
</q-card-section>
</q-tab-panel> -->
</q-tab-panels> </q-tab-panels>
</q-scroll-area> </q-scroll-area>
<q-card-section class="row items-center"> <q-card-section class="row items-center">

View File

@@ -82,98 +82,6 @@
class="col-4" class="col-4"
/> />
</q-card-section> </q-card-section>
<q-card-section class="row">
<div class="col-2">Dashboard Info Color:</div>
<div class="col-2"></div>
<q-input
outlined
dense
v-model="dash_info_color"
class="col-8"
>
<template v-slot:after>
<q-btn
round
dense
flat
size="sm"
icon="info"
@click="openURL(quasar_color_url)"
>
<q-tooltip>Click to see color options</q-tooltip>
</q-btn>
</template>
</q-input>
</q-card-section>
<q-card-section class="row">
<div class="col-2">Dashboard Positive Color:</div>
<div class="col-2"></div>
<q-input
outlined
dense
v-model="dash_positive_color"
class="col-8"
>
<template v-slot:after>
<q-btn
round
dense
flat
size="sm"
icon="info"
@click="openURL(quasar_color_url)"
>
<q-tooltip>Click to see color options</q-tooltip>
</q-btn>
</template>
</q-input>
</q-card-section>
<q-card-section class="row">
<div class="col-2">Dashboard Negative Color:</div>
<div class="col-2"></div>
<q-input
outlined
dense
v-model="dash_negative_color"
class="col-8"
>
<template v-slot:after>
<q-btn
round
dense
flat
size="sm"
icon="info"
@click="openURL(quasar_color_url)"
>
<q-tooltip>Click to see color options</q-tooltip>
</q-btn>
</template>
</q-input>
</q-card-section>
<q-card-section class="row">
<div class="col-2">Dashboard Warning Color:</div>
<div class="col-2"></div>
<q-input
outlined
dense
v-model="dash_warning_color"
class="col-8"
>
<template v-slot:after>
<q-btn
round
dense
flat
size="sm"
icon="info"
@click="openURL(quasar_color_url)"
>
<q-tooltip>Click to see color options</q-tooltip>
</q-btn>
</template>
</q-input>
</q-card-section>
<q-card-section class="row"> <q-card-section class="row">
<div class="col-2">Client Sort:</div> <div class="col-2">Client Sort:</div>
<div class="col-2"></div> <div class="col-2"></div>
@@ -248,14 +156,9 @@ export default {
tab: "ui", tab: "ui",
splitterModel: 20, splitterModel: 20,
loading_bar_color: "", loading_bar_color: "",
dash_info_color: "",
dash_positive_color: "",
dash_negative_color: "",
dash_warning_color: "",
urlActions: [], urlActions: [],
clear_search_when_switching: true, clear_search_when_switching: true,
date_format: "", date_format: "",
quasar_color_url: "https://quasar.dev/style/color-palette",
clientTreeSortOptions: [ clientTreeSortOptions: [
{ {
label: "Sort alphabetically, moving failing clients to the top", label: "Sort alphabetically, moving failing clients to the top",
@@ -332,10 +235,6 @@ export default {
this.defaultAgentTblTab = r.data.default_agent_tbl_tab; this.defaultAgentTblTab = r.data.default_agent_tbl_tab;
this.clientTreeSort = r.data.client_tree_sort; this.clientTreeSort = r.data.client_tree_sort;
this.loading_bar_color = r.data.loading_bar_color; this.loading_bar_color = r.data.loading_bar_color;
this.dash_info_color = r.data.dash_info_color;
this.dash_positive_color = r.data.dash_positive_color;
this.dash_negative_color = r.data.dash_negative_color;
this.dash_warning_color = r.data.dash_warning_color;
this.clear_search_when_switching = r.data.clear_search_when_switching; this.clear_search_when_switching = r.data.clear_search_when_switching;
this.date_format = r.data.date_format; this.date_format = r.data.date_format;
}); });
@@ -354,10 +253,6 @@ export default {
default_agent_tbl_tab: this.defaultAgentTblTab, default_agent_tbl_tab: this.defaultAgentTblTab,
client_tree_sort: this.clientTreeSort, client_tree_sort: this.clientTreeSort,
loading_bar_color: this.loading_bar_color, loading_bar_color: this.loading_bar_color,
dash_info_color: this.dash_info_color,
dash_positive_color: this.dash_positive_color,
dash_negative_color: this.dash_negative_color,
dash_warning_color: this.dash_warning_color,
clear_search_when_switching: this.clear_search_when_switching, clear_search_when_switching: this.clear_search_when_switching,
date_format: this.date_format, date_format: this.date_format,
}; };

View File

@@ -11,17 +11,7 @@
:style="maximized ? '' : 'width: 90vw; max-width: 90vw'" :style="maximized ? '' : 'width: 90vw; max-width: 90vw'"
> >
<q-bar> <q-bar>
<span class="q-pr-sm">{{ title }}</span> {{ title }}
<q-btn
v-if="!script && openAIEnabled"
size="xs"
:disable="loading"
dense
label="Generate Script"
color="primary"
no-caps
@click="generateScriptOpenAI"
/>
<q-space /> <q-space />
<q-btn <q-btn
dense dense
@@ -67,133 +57,105 @@
><br />Add one to get rid of this warning. Ignore if windows. ><br />Add one to get rid of this warning. Ignore if windows.
</q-banner> </q-banner>
<div class="row q-pa-sm"> <div class="row q-pa-sm">
<q-scroll-area <div class="col-4 q-gutter-sm q-pr-sm">
:thumb-style="{ <q-input
right: '4px', filled
borderRadius: '5px', dense
width: '5px', :readonly="readonly"
opacity: 0.75, v-model="formScript.name"
}" label="Name"
:bar-style="{ :rules="[(val) => !!val || '*Required']"
right: '2px', hide-bottom-space
borderRadius: '9px', />
width: '9px', <q-input
opacity: 0.2, filled
}" dense
class="col-4 q-mb-none q-pb-none" :readonly="readonly"
:style="{ height: `${maximized ? '82vh' : '64vh'}` }" v-model="formScript.description"
> label="Description"
<div class="q-gutter-sm q-pr-sm"> />
<q-input <q-select
filled :readonly="readonly"
dense options-dense
:readonly="readonly" filled
v-model="formScript.name" dense
label="Name" v-model="formScript.shell"
:rules="[(val) => !!val || '*Required']" :options="shellOptions"
hide-bottom-space emit-value
/> map-options
<q-input label="Shell Type"
filled />
dense <tactical-dropdown
:readonly="readonly" v-model="formScript.supported_platforms"
v-model="formScript.description" :options="agentPlatformOptions"
label="Description" label="Supported Platforms (All supported if blank)"
/> clearable
<q-select mapOptions
:readonly="readonly" filled
options-dense multiple
filled :readonly="readonly"
dense />
v-model="formScript.shell" <tactical-dropdown
:options="shellOptions" filled
emit-value v-model="formScript.category"
map-options :options="categories"
label="Shell Type" use-input
/> clearable
<tactical-dropdown new-value-mode="add-unique"
v-model="formScript.supported_platforms" filterable
:options="agentPlatformOptions" label="Category"
label="Supported Platforms (All supported if blank)" :readonly="readonly"
clearable hide-bottom-space
mapOptions />
filled <tactical-dropdown
multiple v-model="formScript.args"
:readonly="readonly" label="Script Arguments (press Enter after typing each argument)"
/> filled
<tactical-dropdown use-input
filled multiple
v-model="formScript.category" hide-dropdown-icon
:options="categories" input-debounce="0"
use-input new-value-mode="add"
clearable :readonly="readonly"
new-value-mode="add-unique" />
filterable <q-input
label="Category" type="number"
:readonly="readonly" filled
hide-bottom-space dense
/> :readonly="readonly"
<tactical-dropdown v-model.number="formScript.default_timeout"
v-model="formScript.args" label="Timeout (seconds)"
label="Script Arguments (press Enter after typing each argument)" :rules="[(val) => val >= 5 || 'Minimum is 5']"
filled hide-bottom-space
use-input />
multiple <q-checkbox
hide-dropdown-icon v-model="formScript.run_as_user"
input-debounce="0" label="Run As User (Windows only)"
new-value-mode="add" >
:readonly="readonly" <q-tooltip
/> >Setting this value on the script model will always override any
<tactical-dropdown 'Run As User' checkboxes in the UI and force this script to
v-model="formScript.env_vars" always be run in the context of the logged in user. If no user
:label="envVarsLabel" is logged in, the script will not run and an error will be
filled returned. Not supported on Windows Server.
use-input </q-tooltip>
multiple </q-checkbox>
hide-dropdown-icon <q-input
input-debounce="0" label="Syntax"
new-value-mode="add" type="textarea"
:readonly="readonly" style="height: 150px; overflow-y: auto; resize: none"
/> v-model="formScript.syntax"
<q-input dense
type="number" filled
filled :readonly="readonly"
dense />
:readonly="readonly" </div>
v-model.number="formScript.default_timeout"
label="Timeout (seconds)"
:rules="[(val) => val >= 5 || 'Minimum is 5']"
hide-bottom-space
/>
<q-checkbox
v-model="formScript.run_as_user"
label="Run As User (Windows only)"
>
<q-tooltip
>Setting this value on the script model will always override
any 'Run As User' checkboxes in the UI and force this script
to always be run in the context of the logged in user. If no
user is logged in, the script will not run and an error will
be returned.
</q-tooltip>
</q-checkbox>
<q-input
label="Syntax"
type="textarea"
style="height: 150px; overflow-y: auto; resize: none"
v-model="formScript.syntax"
dense
filled
:readonly="readonly"
/>
</div>
</q-scroll-area>
<v-ace-editor <v-ace-editor
v-model:value="formScript.script_body" v-model:value="formScript.script_body"
class="col-8" class="col-8"
:lang="lang" :lang="lang"
:theme="$q.dark.isActive ? 'tomorrow_night_eighties' : 'tomorrow'" :theme="$q.dark.isActive ? 'tomorrow_night_eighties' : 'tomorrow'"
:style="{ height: `${maximized ? '82vh' : '64vh'}` }" :style="{ height: `${maximized ? '87vh' : '64vh'}` }"
wrap wrap
:printMargin="false" :printMargin="false"
:options="{ fontSize: '14px' }" :options="{ fontSize: '14px' }"
@@ -247,11 +209,9 @@
<script> <script>
// composable imports // composable imports
import { ref, computed, onMounted } from "vue"; import { ref, computed, onMounted } from "vue";
import { useStore } from "vuex";
import { useQuasar, useDialogPluginComponent } from "quasar"; import { useQuasar, useDialogPluginComponent } from "quasar";
import { saveScript, editScript, downloadScript } from "@/api/scripts"; import { saveScript, editScript, downloadScript } from "@/api/scripts";
import { useAgentDropdown, agentPlatformOptions } from "@/composables/agents"; import { useAgentDropdown, agentPlatformOptions } from "@/composables/agents";
import { generateScript } from "@/api/core";
import { notifySuccess } from "@/utils/notify"; import { notifySuccess } from "@/utils/notify";
// ui imports // ui imports
@@ -269,7 +229,6 @@ import "ace-builds/src-noconflict/theme-tomorrow";
// static data // static data
import { shellOptions } from "@/composables/scripts"; import { shellOptions } from "@/composables/scripts";
import { envVarsLabel } from "@/constants/constants";
export default { export default {
name: "ScriptFormModal", name: "ScriptFormModal",
@@ -295,10 +254,6 @@ export default {
const { dialogRef, onDialogHide, onDialogOK } = useDialogPluginComponent(); const { dialogRef, onDialogHide, onDialogOK } = useDialogPluginComponent();
const $q = useQuasar(); const $q = useQuasar();
// setup store
const store = useStore();
const openAIEnabled = computed(() => store.state.openAIIntegrationEnabled);
// setup agent dropdown // setup agent dropdown
const { agent, agentOptions, getAgentOptions } = useAgentDropdown(); const { agent, agentOptions, getAgentOptions } = useAgentDropdown();
@@ -311,7 +266,6 @@ export default {
args: [], args: [],
script_body: "", script_body: "",
run_as_user: false, run_as_user: false,
env_vars: [],
}); });
if (props.clone) script.value.name = `(Copy) ${script.value.name}`; if (props.clone) script.value.name = `(Copy) ${script.value.name}`;
@@ -388,23 +342,6 @@ export default {
}); });
} }
function generateScriptOpenAI() {
$q.dialog({
title: "Ask ChatGPT what you need!",
prompt: {
model: `${lang.value} code that `,
type: "text",
},
cancel: true,
persistent: true,
}).onOk(async (data) => {
const completion = await generateScript({
prompt: data,
});
script.value.script_body = completion;
});
}
// component life cycle hooks // component life cycle hooks
onMounted(async () => { onMounted(async () => {
agentLoading.value = true; agentLoading.value = true;
@@ -426,16 +363,13 @@ export default {
// non-reactive data // non-reactive data
shellOptions, shellOptions,
agentPlatformOptions, agentPlatformOptions,
envVarsLabel,
//computed //computed
title, title,
openAIEnabled,
//methods //methods
submitForm, submitForm,
openTestScriptModal, openTestScriptModal,
generateScriptOpenAI,
// quasar dialog plugin // quasar dialog plugin
dialogRef, dialogRef,

View File

@@ -286,10 +286,15 @@
</template> </template>
</q-tree> </q-tree>
</div> </div>
<tactical-table <q-table
v-if="tableView" v-if="tableView"
dense dense
:table-class="{
'table-bgcolor': !$q.dark.isActive,
'table-bgcolor-dark': $q.dark.isActive,
}"
:style="{ 'max-height': `${$q.screen.height - 182}px` }" :style="{ 'max-height': `${$q.screen.height - 182}px` }"
class="tbl-sticky"
:rows="visibleScripts" :rows="visibleScripts"
:columns="columns" :columns="columns"
:loading="loading" :loading="loading"
@@ -299,7 +304,6 @@
binary-state-sort binary-state-sort
virtual-scroll virtual-scroll
:rows-per-page-options="[0]" :rows-per-page-options="[0]"
column-select
> >
<template v-slot:header-cell-favorite="props"> <template v-slot:header-cell-favorite="props">
<q-th :props="props" auto-width> <q-th :props="props" auto-width>
@@ -421,7 +425,7 @@
</q-list> </q-list>
</q-menu> </q-menu>
<!-- favorite --> <!-- favorite -->
<q-td key="favorite" :props="props"> <q-td>
<q-icon <q-icon
v-if="props.row.favorite" v-if="props.row.favorite"
color="yellow-8" color="yellow-8"
@@ -430,7 +434,7 @@
/> />
</q-td> </q-td>
<!-- shell icon --> <!-- shell icon -->
<q-td key="shell" :props="props"> <q-td>
<q-icon <q-icon
v-if="props.row.shell === 'powershell'" v-if="props.row.shell === 'powershell'"
name="mdi-powershell" name="mdi-powershell"
@@ -465,7 +469,7 @@
</q-icon> </q-icon>
</q-td> </q-td>
<!-- supported platforms --> <!-- supported platforms -->
<q-td key="supported_platforms" :props="props"> <q-td>
<q-badge <q-badge
v-if=" v-if="
!props.row.supported_platforms || !props.row.supported_platforms ||
@@ -483,11 +487,7 @@
> >
</q-td> </q-td>
<!-- name --> <!-- name -->
<q-td <q-td :style="{ color: props.row.hidden ? 'grey' : '' }">
key="name"
:props="props"
:style="{ color: props.row.hidden ? 'grey' : '' }"
>
{{ truncateText(props.row.name, 50) }} {{ truncateText(props.row.name, 50) }}
<q-tooltip <q-tooltip
v-if="props.row.name.length >= 50" v-if="props.row.name.length >= 50"
@@ -497,7 +497,7 @@
</q-tooltip> </q-tooltip>
</q-td> </q-td>
<!-- args --> <!-- args -->
<q-td key="args" :props="props"> <q-td>
<span v-if="props.row.args.length > 0"> <span v-if="props.row.args.length > 0">
{{ truncateText(props.row.args.toString(), 30) }} {{ truncateText(props.row.args.toString(), 30) }}
<q-tooltip <q-tooltip
@@ -509,8 +509,8 @@
</span> </span>
</q-td> </q-td>
<q-td key="category" :props="props">{{ props.row.category }}</q-td> <q-td>{{ props.row.category }}</q-td>
<q-td key="desc" :props="props"> <q-td>
{{ truncateText(props.row.description, 30) }} {{ truncateText(props.row.description, 30) }}
<q-tooltip <q-tooltip
v-if="props.row.description.length >= 30" v-if="props.row.description.length >= 30"
@@ -518,13 +518,10 @@
>{{ props.row.description }}</q-tooltip >{{ props.row.description }}</q-tooltip
> >
</q-td> </q-td>
<q-td key="default_timeout" :props="props">{{ <q-td>{{ props.row.default_timeout }}</q-td>
props.row.default_timeout
}}</q-td>
<q-td></q-td>
</q-tr> </q-tr>
</template> </template>
</tactical-table> </q-table>
</q-card> </q-card>
</q-dialog> </q-dialog>
</template> </template>
@@ -548,13 +545,12 @@ import { notifySuccess } from "@/utils/notify";
import ScriptUploadModal from "@/components/scripts/ScriptUploadModal.vue"; import ScriptUploadModal from "@/components/scripts/ScriptUploadModal.vue";
import ScriptFormModal from "@/components/scripts/ScriptFormModal.vue"; import ScriptFormModal from "@/components/scripts/ScriptFormModal.vue";
import ScriptSnippets from "@/components/scripts/ScriptSnippets.vue"; import ScriptSnippets from "@/components/scripts/ScriptSnippets.vue";
import TacticalTable from "@/components/ui/TacticalTable.vue";
// static data // static data
const columns = [ const columns = [
{ {
name: "favorite", name: "favorite",
label: "Favorites", label: "",
field: "favorite", field: "favorite",
align: "left", align: "left",
sortable: true, sortable: true,
@@ -612,9 +608,6 @@ const columns = [
export default { export default {
name: "ScriptManager", name: "ScriptManager",
components: {
TacticalTable,
},
emits: [...useDialogPluginComponent.emits], emits: [...useDialogPluginComponent.emits],
setup() { setup() {
// setup vuex store // setup vuex store
@@ -874,7 +867,7 @@ export default {
} }
// component life cycle hooks // component life cycle hooks
onMounted(getScripts); onMounted(getScripts());
return { return {
// reactive data // reactive data

View File

@@ -11,17 +11,7 @@
:style="maximized ? '' : 'width: 70vw; max-width: 90vw'" :style="maximized ? '' : 'width: 70vw; max-width: 90vw'"
> >
<q-bar> <q-bar>
<span class="q-pr-sm">{{ title }}</span> {{ title }}
<q-btn
v-if="!snippet && openAIEnabled"
:disable="loading"
dense
size="xs"
label="Generate Script"
color="primary"
no-caps
@click="generateScriptOpenAI"
/>
<q-space /> <q-space />
<q-btn <q-btn
dense dense
@@ -107,9 +97,6 @@
<script> <script>
// composable imports // composable imports
import { ref, computed } from "vue"; import { ref, computed } from "vue";
import { useStore } from "vuex";
import { useQuasar } from "quasar";
import { generateScript } from "@/api/core";
import { useDialogPluginComponent } from "quasar"; import { useDialogPluginComponent } from "quasar";
import { saveScriptSnippet, editScriptSnippet } from "@/api/scripts"; import { saveScriptSnippet, editScriptSnippet } from "@/api/scripts";
import { notifySuccess } from "@/utils/notify"; import { notifySuccess } from "@/utils/notify";
@@ -141,13 +128,6 @@ export default {
// setup quasar plugins // setup quasar plugins
const { dialogRef, onDialogHide, onDialogOK } = useDialogPluginComponent(); const { dialogRef, onDialogHide, onDialogOK } = useDialogPluginComponent();
// setup quasar
const $q = useQuasar();
// setup store
const store = useStore();
const openAIEnabled = computed(() => store.state.openAIIntegrationEnabled);
// snippet form logic // snippet form logic
const snippet = props.snippet const snippet = props.snippet
? ref(Object.assign({}, props.snippet)) ? ref(Object.assign({}, props.snippet))
@@ -187,23 +167,6 @@ export default {
loading.value = false; loading.value = false;
} }
function generateScriptOpenAI() {
$q.dialog({
title: "Ask ChatGPT what you need!",
prompt: {
model: `${lang.value} code that `,
type: "text",
},
cancel: true,
persistent: true,
}).onOk(async (data) => {
const completion = await generateScript({
prompt: data,
});
snippet.value.code = completion;
});
}
return { return {
// reactive data // reactive data
formSnippet: snippet.value, formSnippet: snippet.value,
@@ -216,11 +179,9 @@ export default {
//computed //computed
title, title,
openAIEnabled,
//methods //methods
submitForm, submitForm,
generateScriptOpenAI,
// quasar dialog plugin // quasar dialog plugin
dialogRef, dialogRef,

View File

@@ -93,20 +93,6 @@
/> />
</q-card-section> </q-card-section>
<q-card-section>
<tactical-dropdown
v-model="script.env_vars"
label="Environment Variables"
placeholder="(press Enter after typing each key=value pair)"
filled
use-input
multiple
hide-dropdown-icon
input-debounce="0"
new-value-mode="add"
/>
</q-card-section>
<q-card-section> <q-card-section>
<q-input <q-input
label="Default Timeout" label="Default Timeout"

View File

@@ -45,7 +45,6 @@ export default {
args: props.script.args, args: props.script.args,
shell: props.script.shell, shell: props.script.shell,
run_as_user: props.script.run_as_user, run_as_user: props.script.run_as_user,
env_vars: props.script.env_vars,
}; };
try { try {
ret.value = await testScript(props.agent, data); ret.value = await testScript(props.agent, data);

View File

@@ -102,7 +102,7 @@
<tactical-dropdown <tactical-dropdown
v-if="actionType === 'script'" v-if="actionType === 'script'"
class="col-3" class="col-4"
label="Select script" label="Select script"
v-model="script" v-model="script"
:options="scriptOptions" :options="scriptOptions"
@@ -113,7 +113,7 @@
<q-select <q-select
v-if="actionType === 'script'" v-if="actionType === 'script'"
class="col-3" class="col-5"
dense dense
label="Script Arguments (press Enter after typing each argument)" label="Script Arguments (press Enter after typing each argument)"
filled filled
@@ -126,21 +126,6 @@
new-value-mode="add" new-value-mode="add"
/> />
<q-select
v-if="actionType === 'script'"
class="col-3"
dense
:label="envVarsLabel"
filled
v-model="defaultEnvVars"
use-input
use-chips
multiple
hide-dropdown-icon
input-debounce="0"
new-value-mode="add"
/>
<q-input <q-input
v-if="actionType === 'script'" v-if="actionType === 'script'"
class="col-2" class="col-2"
@@ -225,9 +210,6 @@
<q-item-label caption> <q-item-label caption>
Arguments: {{ element.script_args }} Arguments: {{ element.script_args }}
</q-item-label> </q-item-label>
<q-item-label caption>
Env Vars: {{ element.env_vars }}
</q-item-label>
<q-item-label caption> <q-item-label caption>
Timeout: {{ element.timeout }} Timeout: {{ element.timeout }}
</q-item-label> </q-item-label>
@@ -745,7 +727,6 @@ import { useCheckDropdown } from "@/composables/checks";
import { useCustomFieldDropdown } from "@/composables/core"; import { useCustomFieldDropdown } from "@/composables/core";
import { notifySuccess, notifyError } from "@/utils/notify"; import { notifySuccess, notifyError } from "@/utils/notify";
import { validateTimePeriod } from "@/utils/validation"; import { validateTimePeriod } from "@/utils/validation";
import { envVarsLabel } from "@/constants/constants";
import { import {
convertPeriodToSeconds, convertPeriodToSeconds,
convertToBitArray, convertToBitArray,
@@ -836,15 +817,10 @@ export default {
const { dialogRef, onDialogHide, onDialogOK } = useDialogPluginComponent(); const { dialogRef, onDialogHide, onDialogOK } = useDialogPluginComponent();
// setup dropdowns // setup dropdowns
const { const { script, scriptOptions, defaultTimeout, defaultArgs } =
script, useScriptDropdown(undefined, {
scriptOptions, onMount: true,
defaultTimeout, });
defaultArgs,
defaultEnvVars,
} = useScriptDropdown(undefined, {
onMount: true,
});
// set defaultTimeout to 30 // set defaultTimeout to 30
defaultTimeout.value = 30; defaultTimeout.value = 30;
@@ -938,7 +914,6 @@ export default {
script: script.value, script: script.value,
timeout: defaultTimeout.value, timeout: defaultTimeout.value,
script_args: defaultArgs.value, script_args: defaultArgs.value,
env_vars: defaultEnvVars.value,
}); });
} else if (actionType.value === "cmd") { } else if (actionType.value === "cmd") {
task.value.actions.push({ task.value.actions.push({
@@ -952,7 +927,6 @@ export default {
// clear fields after add // clear fields after add
script.value = null; script.value = null;
defaultArgs.value = []; defaultArgs.value = [];
defaultEnvVars.value = [];
defaultTimeout.value = 30; defaultTimeout.value = 30;
command.value = ""; command.value = "";
} }
@@ -1115,7 +1089,6 @@ export default {
script, script,
defaultTimeout, defaultTimeout,
defaultArgs, defaultArgs,
defaultEnvVars,
actionType, actionType,
command, command,
shell, shell,
@@ -1143,7 +1116,6 @@ export default {
monthOptions, monthOptions,
taskTypeOptions, taskTypeOptions,
taskInstancePolicyOptions, taskInstancePolicyOptions,
envVarsLabel,
// methods // methods
submit, submit,

View File

@@ -1,107 +0,0 @@
<template>
<q-table
:columns="localColumns"
:visible-columns="visibleColumns"
:table-class="{
'table-bgcolor': !$q.dark.isActive,
'table-bgcolor-dark': $q.dark.isActive,
'column-bgcolor-dark': $q.dark.isActive && columnSelect,
'column-bgcolor': !$q.dark.isActive && columnSelect,
'sticky-header-right-column': columnSelect,
'tbl-sticky': !columnSelect,
}"
v-bind="$attrs"
>
<template v-for="(_, slot) in $slots" v-slot:[slot]="scope">
<slot :name="slot" v-bind="scope || {}" />
</template>
<template v-slot:header-cell-columnSelect="props">
<q-th :props="props" auto-width>
<q-btn dense flat icon="more_horiz">
<q-menu>
<q-option-group
v-model="visibleColumns"
:options="columnOptions"
type="checkbox"
/>
</q-menu>
</q-btn>
</q-th>
</template>
</q-table>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
inheritAttrs: false,
});
</script>
<script setup lang="ts">
import { ref } from "vue";
import { type QTableColumn } from "quasar";
const props = withDefaults(
defineProps<{
columns: QTableColumn[];
columnSelect?: boolean;
excludeColumns?: string[];
}>(),
{ columnSelect: false, excludeColumns: () => ["columnSelect"] }
);
// save a non-reactive copy of columns to modify
const localColumns: QTableColumn[] = Object.assign([], props.columns);
if (props.columnSelect)
localColumns.push({
name: "columnSelect",
label: "Column Select",
field: "columnSelect",
});
const visibleColumns = ref(localColumns.map((column) => column.name));
const columnOptions = ref(
localColumns
.filter((column) => !props.excludeColumns.includes(column.name))
.map((column) => ({ label: column.label, value: column.name }))
);
</script>
<style lang="sass">
.column-bgcolor-dark
td:last-child
/* bg color is important for td; just specify one */
background-color: #1d1d1d
.column-bgcolor
td:last-child
/* bg color is important for td; just specify one */
background-color: #ffffff
.sticky-header-right-column
tr th
position: sticky
/* higher than z-index for td below */
z-index: 2
/* this will be the loading indicator */
thead tr:last-child th
/* height of all previous header rows */
top: 48px
/* highest z-index */
z-index: 3
thead tr:last-child th
top: 0
z-index: 1
tr:last-child th:last-child
/* highest z-index */
z-index: 3
td:last-child
z-index: 1
td:last-child, th:last-child
position: sticky
right: 0
/* prevent scrolling behind sticky top row on focus */
tbody
/* height of all previous header rows */
scroll-margin-top: 48px
</style>

View File

@@ -31,7 +31,7 @@ export function useUserDropdown(onMount = false) {
} }
if (onMount) { if (onMount) {
onMounted(getUserOptions); onMounted(getUserOptions());
} }
return { return {

View File

@@ -1,5 +1,4 @@
import { computed, ref } from "vue"; import { ref } from "vue";
import { useStore } from "vuex";
import { fetchAgents } from "@/api/agents"; import { fetchAgents } from "@/api/agents";
import { formatAgentOptions } from "@/utils/format"; import { formatAgentOptions } from "@/utils/format";
@@ -29,16 +28,13 @@ export function useAgentDropdown() {
} }
export function cmdPlaceholder(shell) { export function cmdPlaceholder(shell) {
const store = useStore(); if (shell === "cmd") return "rmdir /S /Q C:\\Windows\\System32";
const placeholders = computed(() => store.state.run_cmd_placeholder_text); else if (shell === "powershell")
return "Remove-Item -Recurse -Force C:\\Windows\\System32";
if (shell === "cmd") return placeholders.value.cmd; else return "rm -rf --no-preserve-root /";
else if (shell === "powershell") return placeholders.value.powershell;
else return placeholders.value.shell;
} }
export const agentPlatformOptions = [ export const agentPlatformOptions = [
{ value: "windows", label: "Windows" }, { value: "windows", label: "Windows" },
{ value: "linux", label: "Linux" }, { value: "linux", label: "Linux" },
{ value: "darwin", label: "macOS" },
]; ];

View File

@@ -8,7 +8,6 @@ export function useScriptDropdown(setScript = null, { onMount = false } = {}) {
const scriptOptions = ref([]); const scriptOptions = ref([]);
const defaultTimeout = ref(30); const defaultTimeout = ref(30);
const defaultArgs = ref([]); const defaultArgs = ref([]);
const defaultEnvVars = ref([]);
const script = ref(setScript); const script = ref(setScript);
const syntax = ref(""); const syntax = ref("");
const link = ref(""); const link = ref("");
@@ -30,7 +29,6 @@ export function useScriptDropdown(setScript = null, { onMount = false } = {}) {
); );
defaultTimeout.value = tmpScript.timeout; defaultTimeout.value = tmpScript.timeout;
defaultArgs.value = tmpScript.args; defaultArgs.value = tmpScript.args;
defaultEnvVars.value = tmpScript.env_vars;
syntax.value = tmpScript.syntax; syntax.value = tmpScript.syntax;
link.value = link.value =
tmpScript.script_type === "builtin" tmpScript.script_type === "builtin"
@@ -51,7 +49,6 @@ export function useScriptDropdown(setScript = null, { onMount = false } = {}) {
scriptOptions, scriptOptions,
defaultTimeout, defaultTimeout,
defaultArgs, defaultArgs,
defaultEnvVars,
syntax, syntax,
link, link,

View File

@@ -1,10 +1,15 @@
export const GOARCH_AMD64 = "amd64"; const GOARCH_AMD64 = "amd64";
export const GOARCH_i386 = "386"; const GOARCH_i386 = "386";
export const GOARCH_ARM64 = "arm64"; const GOARCH_ARM64 = "arm64";
export const GOARCH_ARM32 = "arm"; const GOARCH_ARM32 = "arm";
export const runAsUserToolTip = const runAsUserToolTip =
"Run in the context of the logged in user. If no user is logged in, the script will not run and an error will be returned."; "Run in the context of the logged in user. If no user is logged in, the script will not run and an error will be returned. Not supported on Windows Server.";
export const envVarsLabel = export {
"Environment vars (press Enter after typing each key=value pair)"; GOARCH_AMD64,
GOARCH_i386,
GOARCH_ARM64,
GOARCH_ARM32,
runAsUserToolTip,
};

View File

@@ -14,27 +14,6 @@
@click="$store.dispatch('reload')" @click="$store.dispatch('reload')"
/> />
</q-banner> </q-banner>
<q-banner
v-if="!hosted && tokenExpired"
inline-actions
class="bg-yellow text-black text-center"
>
<q-icon size="xl" name="warning" />
<span
><br />Your code signing token is no longer valid.<br /><br />
If you have downgraded or cancelled your sponsorship, please delete
your token from the Code Signing modal and refresh to get rid of this
banner.<br /><br />
For any issues or to renew your sponsorship please email
support@amidaware.com<br /><br
/></span>
<q-btn
color="dark"
icon="refresh"
label="Refresh"
@click="$store.dispatch('reload')"
/>
</q-banner>
<q-toolbar> <q-toolbar>
<q-btn <q-btn
dense dense
@@ -56,27 +35,15 @@
Tactical RMM<span class="text-overline q-ml-sm" Tactical RMM<span class="text-overline q-ml-sm"
>v{{ currentTRMMVersion }}</span >v{{ currentTRMMVersion }}</span
> >
<!-- update check --> <span class="text-overline q-ml-md" v-if="updateAvailable()"
<q-chip ><q-badge color="warning"
v-if="updateAvailable" ><a :href="latestReleaseURL" target="_blank"
class="text-overline q-ml-sm" >v{{ latestTRMMVersion }} available</a
:color="dash_warning_color" ></q-badge
icon="update" ></span
dense
><a :href="latestReleaseURL" target="_blank"
>v{{ latestTRMMVersion }} available</a
></q-chip
>
<!-- cert expiring soon check -->
<q-chip
v-if="daysUntilCertExpires <= 15"
dense
:color="dash_negative_color"
text-color="black"
icon="warning"
>Certificate expires in {{ daysUntilCertExpires }} days</q-chip
> >
</q-toolbar-title> </q-toolbar-title>
<!-- temp dark mode toggle --> <!-- temp dark mode toggle -->
<q-toggle <q-toggle
v-model="darkMode" v-model="darkMode"
@@ -106,11 +73,7 @@
</q-item> </q-item>
<q-item> <q-item>
<q-item-section avatar> <q-item-section avatar>
<q-icon <q-icon name="power_off" size="sm" color="negative" />
name="power_off"
size="sm"
:color="dash_negative_color"
/>
</q-item-section> </q-item-section>
<q-item-section no-wrap> <q-item-section no-wrap>
@@ -129,11 +92,7 @@
</q-item> </q-item>
<q-item> <q-item>
<q-item-section avatar> <q-item-section avatar>
<q-icon <q-icon name="power_off" size="sm" color="negative" />
name="power_off"
size="sm"
:color="dash_negative_color"
/>
</q-item-section> </q-item-section>
<q-item-section no-wrap> <q-item-section no-wrap>
@@ -160,32 +119,6 @@
<q-item-label>Preferences</q-item-label> <q-item-label>Preferences</q-item-label>
</q-item-section> </q-item-section>
</q-item> </q-item>
<q-item clickable>
<q-item-section>Account</q-item-section>
<q-item-section side>
<q-icon name="keyboard_arrow_right" />
</q-item-section>
<q-menu anchor="top end" self="top start">
<q-list>
<q-item
clickable
v-ripple
@click="resetPassword"
v-close-popup
>
<q-item-section>
<q-item-label>Reset Password</q-item-label>
</q-item-section>
</q-item>
<q-item clickable v-ripple @click="reset2FA" v-close-popup>
<q-item-section>
<q-item-label>Reset 2FA</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-item>
<q-item to="/expired" exact> <q-item to="/expired" exact>
<q-item-section> <q-item-section>
<q-item-label>Logout</q-item-label> <q-item-label>Logout</q-item-label>
@@ -207,13 +140,10 @@ import { useQuasar } from "quasar";
import { useStore } from "vuex"; import { useStore } from "vuex";
import axios from "axios"; import axios from "axios";
import { getWSUrl } from "@/websocket/channels"; import { getWSUrl } from "@/websocket/channels";
import { resetTwoFactor } from "@/api/accounts";
import { notifySuccess } from "@/utils/notify";
// ui imports // ui imports
import AlertsIcon from "@/components/AlertsIcon.vue"; import AlertsIcon from "@/components/AlertsIcon.vue";
import UserPreferences from "@/components/modals/coresettings/UserPreferences.vue"; import UserPreferences from "@/components/modals/coresettings/UserPreferences.vue";
import ResetPass from "@/components/accounts/ResetPass.vue";
export default { export default {
name: "MainLayout", name: "MainLayout",
@@ -237,9 +167,6 @@ export default {
const needRefresh = computed(() => store.state.needrefresh); const needRefresh = computed(() => store.state.needrefresh);
const user = computed(() => store.state.username); const user = computed(() => store.state.username);
const hosted = computed(() => store.state.hosted); const hosted = computed(() => store.state.hosted);
const tokenExpired = computed(() => store.state.tokenExpired);
const dash_warning_color = computed(() => store.state.dash_warning_color);
const dash_negative_color = computed(() => store.state.dash_negative_color);
const latestReleaseURL = computed(() => { const latestReleaseURL = computed(() => {
return latestTRMMVersion.value return latestTRMMVersion.value
@@ -253,31 +180,10 @@ export default {
}).onOk(() => store.dispatch("getDashInfo")); }).onOk(() => store.dispatch("getDashInfo"));
} }
function resetPassword() {
$q.dialog({
component: ResetPass,
});
}
function reset2FA() {
$q.dialog({
title: "Reset 2FA",
message: "Are you sure you would like to reset your 2FA token?",
cancel: true,
persistent: true,
}).onOk(async () => {
try {
const ret = await resetTwoFactor();
notifySuccess(ret, 3000);
} catch {}
});
}
const serverCount = ref(0); const serverCount = ref(0);
const serverOfflineCount = ref(0); const serverOfflineCount = ref(0);
const workstationCount = ref(0); const workstationCount = ref(0);
const workstationOfflineCount = ref(0); const workstationOfflineCount = ref(0);
const daysUntilCertExpires = ref(100);
const ws = ref(null); const ws = ref(null);
@@ -285,13 +191,6 @@ export default {
// moved computed token inside the function since it is not refreshing // moved computed token inside the function since it is not refreshing
// when ws is closed causing ws to connect with expired token // when ws is closed causing ws to connect with expired token
const token = computed(() => store.state.token); const token = computed(() => store.state.token);
if (!token.value) {
console.log(
"Access token is null or invalid, not setting up WebSocket"
);
return;
}
console.log("Starting websocket"); console.log("Starting websocket");
let url = getWSUrl("dashinfo", token.value); let url = getWSUrl("dashinfo", token.value);
ws.value = new WebSocket(url); ws.value = new WebSocket(url);
@@ -304,7 +203,6 @@ export default {
serverOfflineCount.value = data.total_server_offline_count; serverOfflineCount.value = data.total_server_offline_count;
workstationCount.value = data.total_workstation_count; workstationCount.value = data.total_workstation_count;
workstationOfflineCount.value = data.total_workstation_offline_count; workstationOfflineCount.value = data.total_workstation_offline_count;
daysUntilCertExpires.value = data.days_until_cert_expires;
}; };
ws.value.onclose = (e) => { ws.value.onclose = (e) => {
try { try {
@@ -328,18 +226,13 @@ export default {
poll.value = setInterval(() => { poll.value = setInterval(() => {
store.dispatch("checkVer"); store.dispatch("checkVer");
store.dispatch("getDashInfo", false); store.dispatch("getDashInfo", false);
}, 60 * 4 * 1000); }, 60 * 5 * 1000);
} }
const updateAvailable = computed(() => { function updateAvailable() {
if ( if (latestTRMMVersion.value === "error" || hosted.value) return false;
latestTRMMVersion.value === "error" ||
hosted.value ||
currentTRMMVersion.value?.includes("-dev")
)
return false;
return currentTRMMVersion.value !== latestTRMMVersion.value; return currentTRMMVersion.value !== latestTRMMVersion.value;
}); }
onMounted(() => { onMounted(() => {
setupWS(); setupWS();
@@ -360,22 +253,15 @@ export default {
serverOfflineCount, serverOfflineCount,
workstationCount, workstationCount,
workstationOfflineCount, workstationOfflineCount,
daysUntilCertExpires,
latestReleaseURL, latestReleaseURL,
currentTRMMVersion, currentTRMMVersion,
latestTRMMVersion, latestTRMMVersion,
user, user,
needRefresh, needRefresh,
darkMode, darkMode,
hosted,
tokenExpired,
dash_warning_color,
dash_negative_color,
// methods // methods
showUserPreferences, showUserPreferences,
resetPassword,
reset2FA,
updateAvailable, updateAvailable,
}; };
}, },

View File

@@ -193,7 +193,6 @@ export default {
value: script.id, value: script.id,
timeout: script.default_timeout, timeout: script.default_timeout,
args: script.args, args: script.args,
env_vars: script.env_vars,
}); });
} else if (cat === "Unassigned" && !script.category) { } else if (cat === "Unassigned" && !script.category) {
tmp.push({ tmp.push({
@@ -201,7 +200,6 @@ export default {
value: script.id, value: script.id,
timeout: script.default_timeout, timeout: script.default_timeout,
args: script.args, args: script.args,
env_vars: script.env_vars,
}); });
} }
}); });

View File

@@ -17,7 +17,6 @@ export default function () {
agentPlatform: "windows", agentPlatform: "windows",
agentTableLoading: false, agentTableLoading: false,
needrefresh: false, needrefresh: false,
tokenExpired: false,
refreshSummaryTab: false, refreshSummaryTab: false,
tableHeight: "300px", tableHeight: "300px",
tabHeight: "300px", tabHeight: "300px",
@@ -33,16 +32,6 @@ export default function () {
currentTRMMVersion: null, currentTRMMVersion: null,
latestTRMMVersion: null, latestTRMMVersion: null,
dateFormat: "MMM-DD-YYYY - HH:mm", dateFormat: "MMM-DD-YYYY - HH:mm",
openAIIntegrationEnabled: false,
dash_info_color: "info",
dash_positive_color: "positive",
dash_negative_color: "negative",
dash_warning_color: "warning",
run_cmd_placeholder_text: {
cmd: "rmdir /S /Q C:\\Windows\\System32",
powershell: "Remove-Item -Recurse -Force C:\\Windows\\System32",
shell: "rm -rf --no-preserve-root /",
},
}; };
}, },
getters: { getters: {
@@ -94,9 +83,6 @@ export default function () {
SET_REFRESH_NEEDED(state, action) { SET_REFRESH_NEEDED(state, action) {
state.needrefresh = action; state.needrefresh = action;
}, },
SET_TOKEN_EXPIRED(state, action) {
state.tokenExpired = action;
},
SET_SPLITTER(state, val) { SET_SPLITTER(state, val) {
// top toolbar is 50px. Filebar is 40px and agent filter tabs are 44px // top toolbar is 50px. Filebar is 40px and agent filter tabs are 44px
state.tableHeight = `${Screen.height - 50 - 40 - 78 - val}px`; state.tableHeight = `${Screen.height - 50 - 40 - 78 - val}px`;
@@ -146,24 +132,6 @@ export default function () {
setDateFormat(state, val) { setDateFormat(state, val) {
state.dateFormat = val; state.dateFormat = val;
}, },
setOpenAIIntegrationStatus(state, val) {
state.openAIIntegrationEnabled = val;
},
setDashInfoColor(state, val) {
state.dash_info_color = val;
},
setDashPositiveColor(state, val) {
state.dash_positive_color = val;
},
setDashNegativeColor(state, val) {
state.dash_negative_color = val;
},
setDashWarningColor(state, val) {
state.dash_warning_color = val;
},
setRunCmdPlaceholders(state, obj) {
state.run_cmd_placeholder_text = obj;
},
}, },
actions: { actions: {
setClientTreeSplitter(context, val) { setClientTreeSplitter(context, val) {
@@ -188,9 +156,9 @@ export default function () {
} }
if (clearTreeSelected) commit("destroySubTable"); if (clearTreeSelected) commit("destroySubTable");
dispatch("getDashInfo", false);
dispatch("loadAgents"); dispatch("loadAgents");
dispatch("loadTree"); dispatch("loadTree");
dispatch("getDashInfo", false);
}, },
async loadAgents({ state, commit }) { async loadAgents({ state, commit }) {
commit("AGENT_TABLE_LOADING", true); commit("AGENT_TABLE_LOADING", true);
@@ -222,111 +190,106 @@ export default function () {
commit("AGENT_TABLE_LOADING", false); commit("AGENT_TABLE_LOADING", false);
}, },
async getDashInfo({ commit }, edited = true) { async getDashInfo(context, edited = true) {
const { data } = await axios.get("/core/dashinfo/"); const { data } = await axios.get("/core/dashinfo/");
commit("setDashInfoColor", data.dash_info_color);
commit("setDashPositiveColor", data.dash_positive_color);
commit("setDashNegativeColor", data.dash_negative_color);
commit("setDashWarningColor", data.dash_warning_color);
if (edited) { if (edited) {
LoadingBar.setDefaults({ color: data.loading_bar_color }); LoadingBar.setDefaults({ color: data.loading_bar_color });
commit( context.commit(
"setClearSearchWhenSwitching", "setClearSearchWhenSwitching",
data.clear_search_when_switching data.clear_search_when_switching
); );
commit("SET_DEFAULT_AGENT_TBL_TAB", data.default_agent_tbl_tab); context.commit(
commit("SET_CLIENT_TREE_SORT", data.client_tree_sort); "SET_DEFAULT_AGENT_TBL_TAB",
commit("SET_CLIENT_SPLITTER", data.client_tree_splitter); data.default_agent_tbl_tab
);
context.commit("SET_CLIENT_TREE_SORT", data.client_tree_sort);
context.commit("SET_CLIENT_SPLITTER", data.client_tree_splitter);
} }
Dark.set(data.dark_mode); Dark.set(data.dark_mode);
commit("setCurrentTRMMVersion", data.trmm_version); context.commit("setCurrentTRMMVersion", data.trmm_version);
commit("setLatestTRMMVersion", data.latest_trmm_ver); context.commit("setLatestTRMMVersion", data.latest_trmm_ver);
commit("SET_AGENT_DBLCLICK_ACTION", data.dbl_click_action); context.commit("SET_AGENT_DBLCLICK_ACTION", data.dbl_click_action);
commit("SET_URL_ACTION", data.url_action); context.commit("SET_URL_ACTION", data.url_action);
commit("setShowCommunityScripts", data.show_community_scripts); context.commit("setShowCommunityScripts", data.show_community_scripts);
commit("SET_HOSTED", data.hosted); context.commit("SET_HOSTED", data.hosted);
commit("SET_TOKEN_EXPIRED", data.token_is_expired);
commit("setOpenAIIntegrationStatus", data.open_ai_integration_enabled);
commit("setRunCmdPlaceholders", data.run_cmd_placeholder_text);
if (data?.date_format !== "") commit("setDateFormat", data.date_format); if (data.date_format && data.date_format !== "")
else commit("setDateFormat", data.default_date_format); context.commit("setDateFormat", data.date_format);
else context.commit("setDateFormat", data.default_date_format);
}, },
loadTree({ commit, state }) { loadTree({ commit, state }) {
setTimeout(() => { axios
axios .get("/clients/")
.get("/clients/") .then((r) => {
.then((r) => { if (r.data.length === 0) {
if (r.data.length === 0) { this.$router.push({ name: "InitialSetup" });
this.$router.push({ name: "InitialSetup" }); }
}
let output = []; let output = [];
for (let client of r.data) { for (let client of r.data) {
let childSites = []; let childSites = [];
for (let site of client.sites) { for (let site of client.sites) {
let siteNode = { let siteNode = {
label: site.name, label: site.name,
id: site.id, id: site.id,
raw: `Site|${site.id}`, raw: `Site|${site.id}`,
header: "generic", header: "generic",
icon: "apartment", icon: "apartment",
selectable: true, selectable: true,
site: site, site: site,
};
if (site.maintenance_mode) {
siteNode["color"] = "green";
} else if (site.failing_checks.error) {
siteNode["color"] = "negative";
} else if (site.failing_checks.warning) {
siteNode["color"] = "warning";
}
childSites.push(siteNode);
}
let clientNode = {
label: client.name,
id: client.id,
raw: `Client|${client.id}`,
header: "root",
icon: "business",
children: childSites,
client: client,
}; };
if (client.maintenance_mode) clientNode["color"] = "green"; if (site.maintenance_mode) {
else if (client.failing_checks.error) { siteNode["color"] = "green";
clientNode["color"] = "negative"; } else if (site.failing_checks.error) {
} else if (client.failing_checks.warning) { siteNode["color"] = "negative";
clientNode["color"] = "warning"; } else if (site.failing_checks.warning) {
siteNode["color"] = "warning";
} }
output.push(clientNode); childSites.push(siteNode);
} }
const sorted = output.sort((a, b) => let clientNode = {
a.label.localeCompare(b.label) label: client.name,
); id: client.id,
if (state.clientTreeSort === "alphafail") { raw: `Client|${client.id}`,
// move failing clients to the top header: "root",
const failing = sorted.filter( icon: "business",
(i) => i.color === "negative" || i.color === "warning" children: childSites,
); client: client,
const ok = sorted.filter( };
(i) => i.color !== "negative" && i.color !== "warning"
); if (client.maintenance_mode) clientNode["color"] = "green";
const sortedByFailing = [...failing, ...ok]; else if (client.failing_checks.error) {
commit("loadTree", sortedByFailing); clientNode["color"] = "negative";
} else { } else if (client.failing_checks.warning) {
commit("loadTree", sorted); clientNode["color"] = "warning";
} }
})
.catch(() => { output.push(clientNode);
state.treeReady = true; }
});
}, 150); const sorted = output.sort((a, b) =>
a.label.localeCompare(b.label)
);
if (state.clientTreeSort === "alphafail") {
// move failing clients to the top
const failing = sorted.filter(
(i) => i.color === "negative" || i.color === "warning"
);
const ok = sorted.filter(
(i) => i.color !== "negative" && i.color !== "warning"
);
const sortedByFailing = [...failing, ...ok];
commit("loadTree", sortedByFailing);
} else {
commit("loadTree", sorted);
}
})
.catch(() => {
state.treeReady = true;
});
}, },
checkVer(context) { checkVer(context) {
axios.get("/core/version/").then((r) => { axios.get("/core/version/").then((r) => {

View File

@@ -68,7 +68,6 @@ export function formatScriptOptions(data) {
value: script.id, value: script.id,
timeout: script.default_timeout, timeout: script.default_timeout,
args: script.args, args: script.args,
env_vars: script.env_vars,
filename: script.filename, filename: script.filename,
syntax: script.syntax, syntax: script.syntax,
script_type: script.script_type, script_type: script.script_type,
@@ -81,7 +80,6 @@ export function formatScriptOptions(data) {
value: script.id, value: script.id,
timeout: script.default_timeout, timeout: script.default_timeout,
args: script.args, args: script.args,
env_vars: script.env_vars,
filename: script.filename, filename: script.filename,
syntax: script.syntax, syntax: script.syntax,
script_type: script.script_type, script_type: script.script_type,
@@ -287,7 +285,7 @@ export function formatDateInputField(isoDateString, noTimezone = false) {
if (noTimezone) { if (noTimezone) {
isoDateString = isoDateString.replace("Z", ""); isoDateString = isoDateString.replace("Z", "");
} }
return date.formatDate(isoDateString, "YYYY-MM-DDTHH:mm"); return date.formatDate(isoDateString, "YYYY-MM-DDTHH:mm:ss");
} }
// converts a local date string "YYYY-MM-DDTHH:mm:ss" to an iso date string with the local timezone // converts a local date string "YYYY-MM-DDTHH:mm:ss" to an iso date string with the local timezone

View File

@@ -173,18 +173,6 @@
</q-menu> </q-menu>
</q-item> </q-item>
<!-- Bulk Run Checks -->
<q-item
clickable
v-close-popup
@click="runChecks(props.node)"
>
<q-item-section side>
<q-icon name="fas fa-check-double" />
</q-item-section>
<q-item-section>Run Checks</q-item-section>
</q-item>
<q-separator></q-separator> <q-separator></q-separator>
<q-item clickable v-close-popup> <q-item clickable v-close-popup>
@@ -452,7 +440,7 @@ export default {
showInstallAgentModal: false, showInstallAgentModal: false,
sitePk: null, sitePk: null,
innerModel: (this.$q.screen.height - 82) / 2, innerModel: (this.$q.screen.height - 82) / 2,
search: this.$route.query.search ? this.$route.query.search : "", search: "",
filterTextLength: 0, filterTextLength: 0,
filterAvailability: "all", filterAvailability: "all",
filterPatchesPending: false, filterPatchesPending: false,
@@ -702,17 +690,6 @@ export default {
}) })
.onOk(() => this.$store.dispatch("refreshDashboard")); .onOk(() => this.$store.dispatch("refreshDashboard"));
}, },
runChecks(node) {
const target = node.children ? "client" : "site";
this.$axios
.post(`/checks/${target}/${node.id}/csbulkrun/`)
.then((r) => {
this.notifySuccess(r.data);
})
.catch((e) => {
console.error(e);
});
},
showToggleMaintenance(node) { showToggleMaintenance(node) {
let data = { let data = {
id: node.id, id: node.id,

View File

@@ -4,17 +4,8 @@
<div class="col"></div> <div class="col"></div>
<div class="col"> <div class="col">
<q-card> <q-card>
<q-card-actions align="center">
<q-btn
label="Getting Started"
color="info"
class="full-width"
href="https://docs.tacticalrmm.com/guide_gettingstarted/"
target="_blank"
/>
</q-card-actions>
<q-card-section class="row items-center"> <q-card-section class="row items-center">
<div class="text-h5 text-weight-bold">Initial Setup</div> <div class="text-h6">Initial Setup</div>
</q-card-section> </q-card-section>
<q-form @submit.prevent="finish"> <q-form @submit.prevent="finish">
<q-card-section> <q-card-section>

View File

@@ -15,7 +15,7 @@
@click="restartMeshService" @click="restartMeshService"
/> />
<q-btn <q-btn
:color="dash_negative_color" color="negative"
size="sm" size="sm"
label="Recover Connection" label="Recover Connection"
icon="fas fa-first-aid" icon="fas fa-first-aid"
@@ -35,7 +35,6 @@
<script> <script>
// composition imports // composition imports
import { ref, computed, onMounted } from "vue"; import { ref, computed, onMounted } from "vue";
import { useStore } from "vuex";
import { useRoute } from "vue-router"; import { useRoute } from "vue-router";
import { useMeta, useQuasar } from "quasar"; import { useMeta, useQuasar } from "quasar";
import { fetchAgentMeshCentralURLs, sendAgentRecoverMesh } from "@/api/agents"; import { fetchAgentMeshCentralURLs, sendAgentRecoverMesh } from "@/api/agents";
@@ -48,17 +47,12 @@ export default {
setup() { setup() {
// vue lifecycle hooks // vue lifecycle hooks
onMounted(() => { onMounted(() => {
dashInfo();
getDashInfo(); getDashInfo();
getMeshURLs(); getMeshURLs();
}); });
// quasar setup // quasar setup
const $q = useQuasar(); const $q = useQuasar();
const store = useStore();
const dash_positive_color = computed(() => store.state.dash_positive_color);
const dash_negative_color = computed(() => store.state.dash_negative_color);
const dash_warning_color = computed(() => store.state.dash_warning_color);
// vue router // vue router
const { params } = useRoute(); const { params } = useRoute();
@@ -70,19 +64,14 @@ export default {
const statusColor = computed(() => { const statusColor = computed(() => {
switch (status.value) { switch (status.value) {
case "online": case "online":
return dash_positive_color.value; return "positive";
case "offline": case "offline":
return dash_warning_color.value; return "warning";
default: default:
return dash_negative_color.value; return "negative";
} }
}); });
// TODO refactor this so we're not calling the api twice
const dashInfo = () => {
store.dispatch("getDashInfo", false);
};
async function getMeshURLs() { async function getMeshURLs() {
$q.loading.show(); $q.loading.show();
try { try {
@@ -142,7 +131,6 @@ export default {
control, control,
status, status,
statusColor, statusColor,
dash_negative_color,
// methods // methods
repairMeshCentral, repairMeshCentral,