add typescript support and stricter formatting/linting
This commit is contained in:
23
.vscode/extensions.json
vendored
Normal file
23
.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"recommendations": [
|
||||
// frontend
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode",
|
||||
"editorconfig.editorconfig",
|
||||
"johnsoncodehk.volar",
|
||||
"wayou.vscode-todo-highlight",
|
||||
|
||||
// python
|
||||
"matangover.mypy",
|
||||
"ms-python.python",
|
||||
|
||||
// golang
|
||||
"golang.go"
|
||||
],
|
||||
"unwantedRecommendations": [
|
||||
"octref.vetur",
|
||||
"hookyqr.beautify",
|
||||
"dbaeumer.jshint",
|
||||
"ms-vscode.vscode-typescript-tslint-plugin"
|
||||
]
|
||||
}
|
53
.vscode/settings.json
vendored
53
.vscode/settings.json
vendored
@@ -1,17 +1,13 @@
|
||||
{
|
||||
"python.defaultInterpreterPath": "api/tacticalrmm/env/bin/python",
|
||||
"python.languageServer": "Pylance",
|
||||
"python.analysis.extraPaths": [
|
||||
"api/tacticalrmm",
|
||||
"api/env",
|
||||
],
|
||||
"python.analysis.extraPaths": ["api/tacticalrmm", "api/env"],
|
||||
"python.analysis.diagnosticSeverityOverrides": {
|
||||
"reportUnusedImport": "error",
|
||||
"reportDuplicateImport": "error",
|
||||
"reportGeneralTypeIssues": "none"
|
||||
},
|
||||
"python.analysis.typeCheckingMode": "basic",
|
||||
"mypy.runUsingActiveInterpreter": true,
|
||||
"python.linting.enabled": true,
|
||||
"python.linting.mypyEnabled": true,
|
||||
"python.linting.mypyArgs": [
|
||||
@@ -20,20 +16,21 @@
|
||||
"--show-column-numbers",
|
||||
"--strict"
|
||||
],
|
||||
"python.linting.ignorePatterns": [
|
||||
"**/site-packages/**/*.py",
|
||||
".vscode/*.py",
|
||||
"**env/**"
|
||||
],
|
||||
"python.formatting.provider": "black",
|
||||
"mypy.targets": ["api/tacticalrmm"],
|
||||
"mypy.runUsingActiveInterpreter": true,
|
||||
"editor.bracketPairColorization.enabled": true,
|
||||
"editor.guides.bracketPairs": true,
|
||||
"editor.formatOnSave": true,
|
||||
"vetur.format.defaultFormatter.js": "prettier",
|
||||
"vetur.format.defaultFormatterOptions": {
|
||||
"prettier": {
|
||||
"semi": true,
|
||||
"printWidth": 120,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"arrowParens": "avoid",
|
||||
}
|
||||
},
|
||||
"vetur.format.options.tabSize": 2,
|
||||
"vetur.format.options.useTabs": false,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.codeActionsOnSave": ["source.fixAll.eslint"],
|
||||
"eslint.validate": ["javascript", "javascriptreact", "typescript", "vue"],
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
"files.watcherExclude": {
|
||||
"files.watcherExclude": {
|
||||
"**/.git/objects/**": true,
|
||||
@@ -54,33 +51,25 @@
|
||||
"**/*.parquet*": true,
|
||||
"**/*.pyc": true,
|
||||
"**/*.zip": true
|
||||
},
|
||||
}
|
||||
},
|
||||
"go.useLanguageServer": true,
|
||||
"[go]": {
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": false,
|
||||
"source.organizeImports": false
|
||||
},
|
||||
"editor.snippetSuggestions": "none",
|
||||
"editor.snippetSuggestions": "none"
|
||||
},
|
||||
"[go.mod]": {
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": true,
|
||||
},
|
||||
"source.organizeImports": true
|
||||
}
|
||||
},
|
||||
"gopls": {
|
||||
"usePlaceholders": true,
|
||||
"completeUnimported": true,
|
||||
"staticcheck": true,
|
||||
},
|
||||
"mypy.targets": [
|
||||
"api/tacticalrmm"
|
||||
],
|
||||
"python.linting.ignorePatterns": [
|
||||
"**/site-packages/**/*.py",
|
||||
".vscode/*.py",
|
||||
"**env/**"
|
||||
]
|
||||
"staticcheck": true
|
||||
}
|
||||
}
|
19
web/.babelrc
19
web/.babelrc
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"plugins": ["@babel/plugin-syntax-dynamic-import"],
|
||||
"env": {
|
||||
"test": {
|
||||
"plugins": ["dynamic-import-node"],
|
||||
"presets": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
{
|
||||
"modules": "commonjs",
|
||||
"targets": {
|
||||
"node": "current"
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
9
web/.editorconfig
Normal file
9
web/.editorconfig
Normal file
@@ -0,0 +1,9 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
9
web/.eslintignore
Normal file
9
web/.eslintignore
Normal file
@@ -0,0 +1,9 @@
|
||||
/dist
|
||||
/src-bex/www
|
||||
/src-capacitor
|
||||
/src-cordova
|
||||
/.quasar
|
||||
/node_modules
|
||||
.eslintrc.js
|
||||
babel.config.js
|
||||
/src-ssr
|
88
web/.eslintrc.js
Normal file
88
web/.eslintrc.js
Normal file
@@ -0,0 +1,88 @@
|
||||
module.exports = {
|
||||
// https://eslint.org/docs/user-guide/configuring#configuration-cascading-and-hierarchy
|
||||
// This option interrupts the configuration hierarchy at this file
|
||||
// Remove this if you have an higher level ESLint config file (it usually happens into a monorepos)
|
||||
root: true,
|
||||
|
||||
// https://eslint.vuejs.org/user-guide/#how-to-use-a-custom-parser
|
||||
// Must use parserOptions instead of "parser" to allow vue-eslint-parser to keep working
|
||||
// `parser: 'vue-eslint-parser'` is already included with any 'plugin:vue/**' config and should be omitted
|
||||
parserOptions: {
|
||||
parser: require.resolve("@typescript-eslint/parser"),
|
||||
extraFileExtensions: [".vue"],
|
||||
},
|
||||
|
||||
env: {
|
||||
browser: true,
|
||||
es2021: true,
|
||||
node: true,
|
||||
"vue/setup-compiler-macros": true,
|
||||
},
|
||||
|
||||
// Rules order is important, please avoid shuffling them
|
||||
extends: [
|
||||
// Base ESLint recommended rules
|
||||
// 'eslint:recommended',
|
||||
|
||||
// https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin#usage
|
||||
// ESLint typescript rules
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
|
||||
// Uncomment any of the lines below to choose desired strictness,
|
||||
// but leave only one uncommented!
|
||||
// See https://eslint.vuejs.org/rules/#available-rules
|
||||
"plugin:vue/vue3-essential", // Priority A: Essential (Error Prevention)
|
||||
// 'plugin:vue/vue3-strongly-recommended', // Priority B: Strongly Recommended (Improving Readability)
|
||||
// 'plugin:vue/vue3-recommended', // Priority C: Recommended (Minimizing Arbitrary Choices and Cognitive Overhead)
|
||||
|
||||
// https://github.com/prettier/eslint-config-prettier#installation
|
||||
// usage with Prettier, provided by 'eslint-config-prettier'.
|
||||
"prettier",
|
||||
],
|
||||
|
||||
plugins: [
|
||||
// required to apply rules which need type information
|
||||
"@typescript-eslint",
|
||||
|
||||
// https://eslint.vuejs.org/user-guide/#why-doesn-t-it-work-on-vue-files
|
||||
// required to lint *.vue files
|
||||
"vue",
|
||||
|
||||
// https://github.com/typescript-eslint/typescript-eslint/issues/389#issuecomment-509292674
|
||||
// Prettier has not been included as plugin to avoid performance impact
|
||||
// add it as an extension for your IDE
|
||||
],
|
||||
|
||||
globals: {
|
||||
ga: "readonly", // Google Analytics
|
||||
cordova: "readonly",
|
||||
__statics: "readonly",
|
||||
__QUASAR_SSR__: "readonly",
|
||||
__QUASAR_SSR_SERVER__: "readonly",
|
||||
__QUASAR_SSR_CLIENT__: "readonly",
|
||||
__QUASAR_SSR_PWA__: "readonly",
|
||||
process: "readonly",
|
||||
Capacitor: "readonly",
|
||||
chrome: "readonly",
|
||||
},
|
||||
|
||||
// add your custom rules here
|
||||
rules: {
|
||||
"prefer-promise-reject-errors": "off",
|
||||
|
||||
quotes: ["warn", "double", { avoidEscape: true }],
|
||||
|
||||
// this rule, if on, would require explicit return type on the `render` function
|
||||
"@typescript-eslint/explicit-function-return-type": "off",
|
||||
|
||||
// in plain CommonJS modules, you can't use `import foo = require('foo')` to pass this rule, so it has to be disabled
|
||||
"@typescript-eslint/no-var-requires": "off",
|
||||
|
||||
// The core 'no-unused-vars' rules (in the eslint:recommended ruleset)
|
||||
// does not work with type definitions
|
||||
"no-unused-vars": "off",
|
||||
|
||||
// allow debugger during development only
|
||||
"no-debugger": process.env.NODE_ENV === "production" ? "error" : "off",
|
||||
},
|
||||
};
|
@@ -3,6 +3,6 @@
|
||||
module.exports = {
|
||||
plugins: [
|
||||
// to edit target browsers: use "browserslist" field in package.json
|
||||
require('autoprefixer')
|
||||
]
|
||||
}
|
||||
require("autoprefixer"),
|
||||
],
|
||||
};
|
||||
|
4
web/.prettierrc
Normal file
4
web/.prettierrc
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"singleQuote": false,
|
||||
"semi": true
|
||||
}
|
@@ -1,18 +1,14 @@
|
||||
const fs = require('fs-extra')
|
||||
let extend = undefined
|
||||
/* eslint-disable */
|
||||
|
||||
/**
|
||||
* The .babelrc file has been created to assist Jest for transpiling.
|
||||
* You should keep your application's babel rules in this file.
|
||||
*/
|
||||
|
||||
if (fs.existsSync('./.babelrc')) {
|
||||
extend = './.babelrc'
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
module.exports = (api) => {
|
||||
return {
|
||||
presets: [
|
||||
'@quasar/babel-preset-app'
|
||||
[
|
||||
"@quasar/babel-preset-app",
|
||||
api.caller((caller) => caller && caller.target === "node")
|
||||
? { targets: { node: "current" } }
|
||||
: {},
|
||||
],
|
||||
extends: extend
|
||||
}
|
||||
],
|
||||
};
|
||||
};
|
||||
|
1406
web/package-lock.json
generated
1406
web/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -6,13 +6,14 @@
|
||||
"scripts": {
|
||||
"serve": "quasar dev",
|
||||
"build": "quasar build",
|
||||
"test:e2e": "cross-env E2E_TEST=true start-test \"quasar dev\" http-get://localhost:8080 \"cypress open\"",
|
||||
"test:e2e:ci": "cross-env E2E_TEST=true start-test \"quasar dev\" http-get://localhost:8080 \"cypress run\""
|
||||
"lint": "eslint --ext .js,.ts,.vue ./",
|
||||
"format": "prettier --write \"**/*.{js,ts,vue,,html,md,json}\" --ignore-path .gitignore"
|
||||
},
|
||||
"dependencies": {
|
||||
"@quasar/extras": "^1.13.5",
|
||||
"apexcharts": "^3.35.0",
|
||||
"axios": "^0.26.1",
|
||||
"core-js": "^3.6.5",
|
||||
"dotenv": "^16.0.0",
|
||||
"qrcode.vue": "^3.3.3",
|
||||
"quasar": "^2.6.6",
|
||||
@@ -20,16 +21,34 @@
|
||||
"vue3-ace-editor": "^2.2.2",
|
||||
"vue3-apexcharts": "^1.4.1",
|
||||
"vuedraggable": "^4.1.0",
|
||||
"vue-router": "^4.0.0",
|
||||
"vuex": "^4.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^5.10.0",
|
||||
"@typescript-eslint/parser": "^5.10.0",
|
||||
"eslint": "^8.10.0",
|
||||
"eslint-plugin-vue": "^8.5.0",
|
||||
"eslint-config-prettier": "^8.1.0",
|
||||
"prettier": "^2.5.1",
|
||||
"@types/node": "^12.20.21",
|
||||
"@quasar/app-webpack": "^3.5.1",
|
||||
"@quasar/cli": "^1.3.2"
|
||||
},
|
||||
"browserslist": [
|
||||
"last 2 Chrome versions",
|
||||
"last 2 Firefox versions",
|
||||
"last 2 Edge versions",
|
||||
"last 1 Safari versions"
|
||||
]
|
||||
"last 10 Chrome versions",
|
||||
"last 10 Firefox versions",
|
||||
"last 4 Edge versions",
|
||||
"last 7 Safari versions",
|
||||
"last 8 Android versions",
|
||||
"last 8 ChromeAndroid versions",
|
||||
"last 8 FirefoxAndroid versions",
|
||||
"last 10 iOS versions",
|
||||
"last 5 Opera versions"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 12.22.1",
|
||||
"npm": ">= 6.13.4",
|
||||
"yarn": ">= 1.21.1"
|
||||
}
|
||||
}
|
@@ -1,38 +1,48 @@
|
||||
require('dotenv').config();
|
||||
const path = require('path');
|
||||
require("dotenv").config();
|
||||
const path = require("path");
|
||||
|
||||
module.exports = function () {
|
||||
return {
|
||||
supportTS: false,
|
||||
supportTS: {
|
||||
tsCheckerConfig: {
|
||||
eslint: {
|
||||
enabled: true,
|
||||
files: "./src/**/*.{ts,tsx,js,jsx,vue}",
|
||||
},
|
||||
},
|
||||
},
|
||||
// https://quasar.dev/quasar-cli/cli-documentation/prefetch-feature
|
||||
// preFetch: true,
|
||||
boot: [
|
||||
'axios',
|
||||
],
|
||||
boot: ["axios"],
|
||||
// https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-css
|
||||
css: [
|
||||
'app.sass'
|
||||
],
|
||||
css: ["app.sass"],
|
||||
// https://github.com/quasarframework/quasar/tree/dev/extras
|
||||
extras: [
|
||||
// 'ionicons-v4',
|
||||
'mdi-v5',
|
||||
'fontawesome-v5',
|
||||
"mdi-v5",
|
||||
"fontawesome-v5",
|
||||
// 'eva-icons',
|
||||
// 'themify',
|
||||
// 'line-awesome',
|
||||
// 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both!
|
||||
|
||||
'roboto-font', // optional, you are not bound to it
|
||||
'material-icons', // optional, you are not bound to it
|
||||
"roboto-font", // optional, you are not bound to it
|
||||
"material-icons", // optional, you are not bound to it
|
||||
],
|
||||
|
||||
// Full list of options: https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-build
|
||||
build: {
|
||||
env: { DEV_API: process.env.DEV_URL, PROD_API: process.env.PROD_URL, DOCKER_BUILD: process.env.DOCKER_BUILD },
|
||||
vueRouterMode: 'history', // available values: 'hash', 'history'
|
||||
env: {
|
||||
DEV_API: process.env.DEV_URL,
|
||||
PROD_API: process.env.PROD_URL,
|
||||
DOCKER_BUILD: process.env.DOCKER_BUILD,
|
||||
},
|
||||
vueRouterMode: "history", // available values: 'hash', 'history'
|
||||
distDir: "dist/",
|
||||
devtool: process.env.NODE_ENV === "production" ? "cheap-module-eval-source-map" : "source-map",
|
||||
devtool:
|
||||
process.env.NODE_ENV === "production"
|
||||
? "cheap-module-eval-source-map"
|
||||
: "source-map",
|
||||
|
||||
// Add dependencies for transpiling with Babel (Array of regexes)
|
||||
// (from node_modules, which are by default not transpiled).
|
||||
@@ -52,8 +62,8 @@ module.exports = function () {
|
||||
extendWebpack(cfg) {
|
||||
cfg.resolve.alias = {
|
||||
...cfg.resolve.alias,
|
||||
"@": path.resolve(__dirname, './src'),
|
||||
}
|
||||
"@": path.resolve(__dirname, "./src"),
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
@@ -62,36 +72,30 @@ module.exports = function () {
|
||||
https: false,
|
||||
host: process.env.DEV_HOST,
|
||||
port: process.env.DEV_PORT,
|
||||
open: false
|
||||
open: false,
|
||||
},
|
||||
|
||||
// https://quasar.dev/quasar-cli/quasar-conf-js#Property%3A-framework
|
||||
framework: {
|
||||
iconSet: 'material-icons', // Quasar icon set
|
||||
lang: 'en-US', // Quasar language pack
|
||||
iconSet: "material-icons", // Quasar icon set
|
||||
lang: "en-US", // Quasar language pack
|
||||
|
||||
// Quasar plugins
|
||||
plugins: [
|
||||
'Dialog',
|
||||
'Loading',
|
||||
'LoadingBar',
|
||||
'Meta',
|
||||
'Notify'
|
||||
],
|
||||
plugins: ["Dialog", "Loading", "LoadingBar", "Meta", "Notify"],
|
||||
config: {
|
||||
loadingBar: {
|
||||
size: "4px"
|
||||
size: "4px",
|
||||
},
|
||||
notify: {
|
||||
position: "top",
|
||||
timeout: 2000,
|
||||
textColor: "white",
|
||||
actions: [{ icon: "close", color: "white" }]
|
||||
actions: [{ icon: "close", color: "white" }],
|
||||
},
|
||||
loading: {
|
||||
delay: 50
|
||||
}
|
||||
}
|
||||
delay: 50,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
// animations: 'all', // --- includes all animations
|
||||
@@ -100,7 +104,7 @@ module.exports = function () {
|
||||
|
||||
// https://quasar.dev/quasar-cli/developing-ssr/configuring-ssr
|
||||
ssr: {
|
||||
pwa: false
|
||||
}
|
||||
}
|
||||
}
|
||||
pwa: false,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
@@ -1,57 +1,63 @@
|
||||
import axios from "axios"
|
||||
import axios from "axios";
|
||||
|
||||
const baseUrl = "/accounts"
|
||||
const baseUrl = "/accounts";
|
||||
|
||||
// user api functions
|
||||
export async function fetchUsers(params = {}) {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/users/`, { params: params })
|
||||
return data
|
||||
} catch (e) { console.error(e) }
|
||||
const { data } = await axios.get(`${baseUrl}/users/`, { params: params });
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
// role api function
|
||||
export async function fetchRoles(params = {}) {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/roles/`, { params: params })
|
||||
return data
|
||||
} catch (e) { console.error(e) }
|
||||
const { data } = await axios.get(`${baseUrl}/roles/`, { params: params });
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function removeRole(id) {
|
||||
const { data } = await axios.delete(`${baseUrl}/roles/${id}/`)
|
||||
return data
|
||||
const { data } = await axios.delete(`${baseUrl}/roles/${id}/`);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function saveRole(payload) {
|
||||
const { data } = await axios.post(`${baseUrl}/roles/`, payload)
|
||||
return data
|
||||
export async function saveRole(role) {
|
||||
const { data } = await axios.post(`${baseUrl}/roles/`, role);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function editRole(id, payload) {
|
||||
const { data } = await axios.put(`${baseUrl}/roles/${id}/`, payload)
|
||||
return data
|
||||
export async function editRole(id, role) {
|
||||
const { data } = await axios.put(`${baseUrl}/roles/${id}/`, role);
|
||||
return data;
|
||||
}
|
||||
|
||||
// api key api functions
|
||||
export async function fetchAPIKeys(params = {}) {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/apikeys/`, { params: params })
|
||||
return data
|
||||
} catch (e) { console.error(e) }
|
||||
const { data } = await axios.get(`${baseUrl}/apikeys/`, { params: params });
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function saveAPIKey(payload) {
|
||||
const { data } = await axios.post(`${baseUrl}/apikeys/`, payload)
|
||||
return data
|
||||
export async function saveAPIKey(apiKey) {
|
||||
const { data } = await axios.post(`${baseUrl}/apikeys/`, apiKey);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function editAPIKey(payload) {
|
||||
const { data } = await axios.put(`${baseUrl}/apikeys/${payload.id}/`, payload)
|
||||
return data
|
||||
export async function editAPIKey(id, apiKey) {
|
||||
const { data } = await axios.put(`${baseUrl}/apikeys/${id}/`, apiKey);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function removeAPIKey(id) {
|
||||
const { data } = await axios.delete(`${baseUrl}/apikeys/${id}/`)
|
||||
return data
|
||||
const { data } = await axios.delete(`${baseUrl}/apikeys/${id}/`);
|
||||
return data;
|
||||
}
|
||||
|
@@ -1,167 +1,234 @@
|
||||
import axios from "axios"
|
||||
import axios from "axios";
|
||||
import { openURL } from "quasar";
|
||||
import { router } from "@/router"
|
||||
import { router } from "@/router";
|
||||
|
||||
const baseUrl = "/agents"
|
||||
const baseUrl = "/agents";
|
||||
|
||||
export function runTakeControl(agent_id) {
|
||||
const url = router.resolve(`/takecontrol/${agent_id}`).href;
|
||||
openURL(url, null, { popup: true, scrollbars: false, location: false, status: false, toolbar: false, menubar: false, width: 1600, height: 900 });
|
||||
openURL(url, null, {
|
||||
popup: true,
|
||||
scrollbars: false,
|
||||
location: false,
|
||||
status: false,
|
||||
toolbar: false,
|
||||
menubar: false,
|
||||
width: 1600,
|
||||
height: 900,
|
||||
});
|
||||
}
|
||||
|
||||
export function openAgentWindow(agent_id) {
|
||||
const url = router.resolve(`/agents/${agent_id}`).href;
|
||||
openURL(url, null, { popup: true, scrollbars: false, location: false, status: false, toolbar: false, menubar: false, width: 1600, height: 900 });
|
||||
openURL(url, null, {
|
||||
popup: true,
|
||||
scrollbars: false,
|
||||
location: false,
|
||||
status: false,
|
||||
toolbar: false,
|
||||
menubar: false,
|
||||
width: 1600,
|
||||
height: 900,
|
||||
});
|
||||
}
|
||||
|
||||
export function runRemoteBackground(agent_id, agentPlatform) {
|
||||
const url = router.resolve(`/remotebackground/${agent_id}?agentPlatform=${agentPlatform}`).href;
|
||||
openURL(url, null, { popup: true, scrollbars: false, location: false, status: false, toolbar: false, menubar: false, width: 1280, height: 900 });
|
||||
const url = router.resolve(
|
||||
`/remotebackground/${agent_id}?agentPlatform=${agentPlatform}`
|
||||
).href;
|
||||
openURL(url, null, {
|
||||
popup: true,
|
||||
scrollbars: false,
|
||||
location: false,
|
||||
status: false,
|
||||
toolbar: false,
|
||||
menubar: false,
|
||||
width: 1280,
|
||||
height: 900,
|
||||
});
|
||||
}
|
||||
|
||||
export async function fetchAgents(params = {}) {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/`, { params: params })
|
||||
return data
|
||||
const { data } = await axios.get(`${baseUrl}/`, { params: params });
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchAgent(agent_id, params = {}) {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/${agent_id}/`, { params: params })
|
||||
return data
|
||||
} catch (e) { console.error(e) }
|
||||
const { data } = await axios.get(`${baseUrl}/${agent_id}/`, {
|
||||
params: params,
|
||||
});
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function editAgent(agent_id, payload) {
|
||||
const { data } = await axios.put(`${baseUrl}/${agent_id}/`, payload)
|
||||
return data
|
||||
const { data } = await axios.put(`${baseUrl}/${agent_id}/`, payload);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function removeAgent(agent_id) {
|
||||
const { data } = await axios.delete(`${baseUrl}/${agent_id}/`)
|
||||
return data
|
||||
const { data } = await axios.delete(`${baseUrl}/${agent_id}/`);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function fetchAgentHistory(agent_id, params = {}) {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/${agent_id}/history/`, { params: params })
|
||||
return data
|
||||
} catch (e) { console.error(e) }
|
||||
const { data } = await axios.get(`${baseUrl}/${agent_id}/history/`, {
|
||||
params: params,
|
||||
});
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchAgentChecks(agent_id, params = {}) {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/${agent_id}/checks/`, { params: params })
|
||||
return data
|
||||
} catch (e) { console.error(e) }
|
||||
const { data } = await axios.get(`${baseUrl}/${agent_id}/checks/`, {
|
||||
params: params,
|
||||
});
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchAgentTasks(agent_id, params = {}) {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/${agent_id}/tasks/`, { params: params })
|
||||
return data
|
||||
} catch (e) { console.error(e) }
|
||||
const { data } = await axios.get(`${baseUrl}/${agent_id}/tasks/`, {
|
||||
params: params,
|
||||
});
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function sendAgentRecovery(agent_id, payload) {
|
||||
const { data } = await axios.post(`${baseUrl}/${agent_id}/recover/`, payload)
|
||||
return data
|
||||
const { data } = await axios.post(`${baseUrl}/${agent_id}/recover/`, payload);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function sendAgentCommand(agent_id, payload) {
|
||||
const { data } = await axios.post(`${baseUrl}/${agent_id}/cmd/`, payload)
|
||||
return data
|
||||
const { data } = await axios.post(`${baseUrl}/${agent_id}/cmd/`, payload);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function refreshAgentWMI(agent_id) {
|
||||
const { data } = await axios.post(`${baseUrl}/${agent_id}/wmi/`)
|
||||
return data
|
||||
const { data } = await axios.post(`${baseUrl}/${agent_id}/wmi/`);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function runScript(agent_id, payload) {
|
||||
const { data } = await axios.post(`${baseUrl}/${agent_id}/runscript/`, payload)
|
||||
return data
|
||||
const { data } = await axios.post(
|
||||
`${baseUrl}/${agent_id}/runscript/`,
|
||||
payload
|
||||
);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function runBulkAction(payload) {
|
||||
const { data } = await axios.post(`${baseUrl}/actions/bulk/`, payload)
|
||||
return data
|
||||
const { data } = await axios.post(`${baseUrl}/actions/bulk/`, payload);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function fetchAgentProcesses(agent_id, params = {}) {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/${agent_id}/processes/`, { params: params })
|
||||
return data
|
||||
const { data } = await axios.get(`${baseUrl}/${agent_id}/processes/`, {
|
||||
params: params,
|
||||
});
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function killAgentProcess(agent_id, pid, params = {}) {
|
||||
const { data } = await axios.delete(`${baseUrl}/${agent_id}/processes/${pid}/`, { params: params })
|
||||
return data
|
||||
const { data } = await axios.delete(
|
||||
`${baseUrl}/${agent_id}/processes/${pid}/`,
|
||||
{ params: params }
|
||||
);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function fetchAgentEventLog(agent_id, logType, days, params = {}) {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/${agent_id}/eventlog/${logType}/${days}/`, { params: params })
|
||||
return data
|
||||
const { data } = await axios.get(
|
||||
`${baseUrl}/${agent_id}/eventlog/${logType}/${days}/`,
|
||||
{ params: params }
|
||||
);
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchAgentMeshCentralURLs(agent_id, params = {}) {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/${agent_id}/meshcentral/`, { params: params })
|
||||
return data
|
||||
const { data } = await axios.get(`${baseUrl}/${agent_id}/meshcentral/`, {
|
||||
params: params,
|
||||
});
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function scheduleAgentReboot(agent_id, payload) {
|
||||
const { data } = await axios.patch(`${baseUrl}/${agent_id}/reboot/`, payload)
|
||||
return data
|
||||
const { data } = await axios.patch(`${baseUrl}/${agent_id}/reboot/`, payload);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function agentRebootNow(agent_id) {
|
||||
const { data } = await axios.post(`${baseUrl}/${agent_id}/reboot/`)
|
||||
return data
|
||||
const { data } = await axios.post(`${baseUrl}/${agent_id}/reboot/`);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function sendAgentRecoverMesh(agent_id, params = {}) {
|
||||
const { data } = await axios.post(`${baseUrl}/${agent_id}/meshcentral/recover/`, { params: params })
|
||||
return data
|
||||
const { data } = await axios.post(
|
||||
`${baseUrl}/${agent_id}/meshcentral/recover/`,
|
||||
{ params: params }
|
||||
);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function sendAgentPing(agent_id, params = {}) {
|
||||
const { data } = await axios.get(`${baseUrl}/${agent_id}/ping/`, { params: params })
|
||||
return data
|
||||
const { data } = await axios.get(`${baseUrl}/${agent_id}/ping/`, {
|
||||
params: params,
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
// agent notes
|
||||
export async function fetchAgentNotes(agent_id, params = {}) {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/${agent_id}/notes/`, { params: params })
|
||||
return data
|
||||
} catch (e) { console.error(e) }
|
||||
const { data } = await axios.get(`${baseUrl}/${agent_id}/notes/`, {
|
||||
params: params,
|
||||
});
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function saveAgentNote(payload) {
|
||||
const { data } = await axios.post(`${baseUrl}/notes/`, payload)
|
||||
return data
|
||||
const { data } = await axios.post(`${baseUrl}/notes/`, payload);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function editAgentNote(pk, payload) {
|
||||
const { data } = await axios.put(`${baseUrl}/notes/${pk}/`, payload)
|
||||
return data
|
||||
const { data } = await axios.put(`${baseUrl}/notes/${pk}/`, payload);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function removeAgentNote(pk) {
|
||||
const { data } = await axios.delete(`${baseUrl}/notes/${pk}/`)
|
||||
return data
|
||||
const { data } = await axios.delete(`${baseUrl}/notes/${pk}/`);
|
||||
return data;
|
||||
}
|
||||
|
@@ -1,15 +1,17 @@
|
||||
import axios from "axios"
|
||||
import axios from "axios";
|
||||
|
||||
const baseUrl = "/automation"
|
||||
const baseUrl = "/automation";
|
||||
|
||||
export async function sendPatchPolicyReset(payload) {
|
||||
const { data } = await axios.post(`${baseUrl}/patchpolicy/reset/`, payload)
|
||||
return data
|
||||
const { data } = await axios.post(`${baseUrl}/patchpolicy/reset/`, payload);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function fetchPolicyChecks(id) {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/policies/${id}/checks/`)
|
||||
return data
|
||||
} catch (e) { console.error(e) }
|
||||
const { data } = await axios.get(`${baseUrl}/policies/${id}/checks/`);
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
@@ -1,37 +1,37 @@
|
||||
import axios from "axios"
|
||||
import axios from "axios";
|
||||
|
||||
const baseUrl = "/checks"
|
||||
const baseUrl = "/checks";
|
||||
|
||||
export async function fetchChecks(params = {}) {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/`, { params: params })
|
||||
return data
|
||||
const { data } = await axios.get(`${baseUrl}/`, { params: params });
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function saveCheck(payload) {
|
||||
const { data } = await axios.post(`${baseUrl}/`, payload)
|
||||
return data
|
||||
const { data } = await axios.post(`${baseUrl}/`, payload);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function updateCheck(id, payload) {
|
||||
const { data } = await axios.put(`${baseUrl}/${id}/`, payload)
|
||||
return data
|
||||
const { data } = await axios.put(`${baseUrl}/${id}/`, payload);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function removeCheck(id) {
|
||||
const { data } = await axios.delete(`${baseUrl}/${id}/`)
|
||||
return data
|
||||
const { data } = await axios.delete(`${baseUrl}/${id}/`);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function resetCheck(id) {
|
||||
const { data } = await axios.post(`${baseUrl}/${id}/reset/`)
|
||||
return data
|
||||
const { data } = await axios.post(`${baseUrl}/${id}/reset/`);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function runAgentChecks(agent_id) {
|
||||
const { data } = await axios.post(`${baseUrl}/${agent_id}/run/`)
|
||||
return data
|
||||
const { data } = await axios.post(`${baseUrl}/${agent_id}/run/`);
|
||||
return data;
|
||||
}
|
@@ -1,81 +1,95 @@
|
||||
import axios from "axios"
|
||||
import axios from "axios";
|
||||
|
||||
const baseUrl = "/clients"
|
||||
const baseUrl = "/clients";
|
||||
|
||||
// client endpoints
|
||||
export async function fetchClients() {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/`)
|
||||
return data
|
||||
} catch (e) { console.error(e) }
|
||||
const { data } = await axios.get(`${baseUrl}/`);
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchClient(id) {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/${id}/`)
|
||||
return data
|
||||
} catch (e) { console.error(e) }
|
||||
const { data } = await axios.get(`${baseUrl}/${id}/`);
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function saveClient(payload) {
|
||||
const { data } = await axios.post(`${baseUrl}/`, payload)
|
||||
return data
|
||||
const { data } = await axios.post(`${baseUrl}/`, payload);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function editClient(id, payload) {
|
||||
const { data } = await axios.put(`${baseUrl}/${id}/`, payload)
|
||||
return data
|
||||
const { data } = await axios.put(`${baseUrl}/${id}/`, payload);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function removeClient(id, params = {}) {
|
||||
const { data } = await axios.delete(`${baseUrl}/${id}/`, { params: params })
|
||||
return data
|
||||
const { data } = await axios.delete(`${baseUrl}/${id}/`, { params: params });
|
||||
return data;
|
||||
}
|
||||
|
||||
// site endpoints
|
||||
export async function fetchSites() {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/sites/`)
|
||||
return data
|
||||
} catch (e) { console.error(e) }
|
||||
const { data } = await axios.get(`${baseUrl}/sites/`);
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchSite(id) {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/sites/${id}/`)
|
||||
return data
|
||||
} catch (e) { console.error(e) }
|
||||
const { data } = await axios.get(`${baseUrl}/sites/${id}/`);
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function saveSite(payload) {
|
||||
const { data } = await axios.post(`${baseUrl}/sites/`, payload)
|
||||
return data
|
||||
const { data } = await axios.post(`${baseUrl}/sites/`, payload);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function editSite(id, payload) {
|
||||
const { data } = await axios.put(`${baseUrl}/sites/${id}/`, payload)
|
||||
return data
|
||||
const { data } = await axios.put(`${baseUrl}/sites/${id}/`, payload);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function removeSite(id, params = {}) {
|
||||
const { data } = await axios.delete(`${baseUrl}/sites/${id}/`, { params: params })
|
||||
return data
|
||||
const { data } = await axios.delete(`${baseUrl}/sites/${id}/`, {
|
||||
params: params,
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
// deployment endpoints
|
||||
export async function fetchDeployments() {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/deployments/`)
|
||||
return data
|
||||
} catch (e) { console.error(e) }
|
||||
const { data } = await axios.get(`${baseUrl}/deployments/`);
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function saveDeployment(payload) {
|
||||
const { data } = await axios.post(`${baseUrl}/deployments/`, payload)
|
||||
return data
|
||||
const { data } = await axios.post(`${baseUrl}/deployments/`, payload);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function removeDeployment(id, params = {}) {
|
||||
const { data } = await axios.delete(`${baseUrl}/deployments/${id}/`, { params: params })
|
||||
return data
|
||||
const { data } = await axios.delete(`${baseUrl}/deployments/${id}/`, {
|
||||
params: params,
|
||||
});
|
||||
return data;
|
||||
}
|
@@ -1,30 +1,40 @@
|
||||
import axios from "axios"
|
||||
import axios from "axios";
|
||||
import { openURL } from "quasar";
|
||||
|
||||
const baseUrl = "/core"
|
||||
const baseUrl = "/core";
|
||||
|
||||
export async function fetchCustomFields(params = {}) {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/customfields/`, { params: params })
|
||||
return data
|
||||
} catch (e) { console.error(e) }
|
||||
const { data } = await axios.get(`${baseUrl}/customfields/`, {
|
||||
params: params,
|
||||
});
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchDashboardInfo(params = {}) {
|
||||
const { data } = await axios.get(`${baseUrl}/dashinfo/`, { params: params })
|
||||
return data
|
||||
const { data } = await axios.get(`${baseUrl}/dashinfo/`, { params: params });
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function fetchURLActions(params = {}) {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/urlaction/`, { params: params })
|
||||
return data
|
||||
} catch (e) { console.error(e) }
|
||||
const { data } = await axios.get(`${baseUrl}/urlaction/`, {
|
||||
params: params,
|
||||
});
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function runURLAction(payload) {
|
||||
try {
|
||||
const { data } = await axios.patch(`${baseUrl}/urlaction/run/`, payload)
|
||||
openURL(data)
|
||||
} catch (e) { console.error(e) }
|
||||
const { data } = await axios.patch(`${baseUrl}/urlaction/run/`, payload);
|
||||
openURL(data);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
@@ -1,35 +1,37 @@
|
||||
import axios from "axios"
|
||||
import axios from "axios";
|
||||
|
||||
const baseUrl = "/logs"
|
||||
const baseUrl = "/logs";
|
||||
|
||||
export async function fetchDebugLog(payload) {
|
||||
try {
|
||||
const { data } = await axios.patch(`${baseUrl}/debug/`, payload)
|
||||
return data
|
||||
} catch (e) { }
|
||||
const { data } = await axios.patch(`${baseUrl}/debug/`, payload);
|
||||
return data;
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
export async function fetchAuditLog(payload) {
|
||||
const { data } = await axios.patch(`${baseUrl}/audit/`, payload)
|
||||
return data
|
||||
const { data } = await axios.patch(`${baseUrl}/audit/`, payload);
|
||||
return data;
|
||||
}
|
||||
|
||||
// pending actions
|
||||
export async function fetchPendingActions(params = {}) {
|
||||
const { data } = await axios.get(`${baseUrl}/pendingactions/`, { params: params })
|
||||
return data
|
||||
const { data } = await axios.get(`${baseUrl}/pendingactions/`, {
|
||||
params: params,
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function fetchAgentPendingActions(agent_id) {
|
||||
try {
|
||||
const { data } = await axios.get(`/agents/${agent_id}/pendingactions/`)
|
||||
return data
|
||||
const { data } = await axios.get(`/agents/${agent_id}/pendingactions/`);
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function deletePendingAction(id) {
|
||||
const { data } = await axios.delete(`${baseUrl}/pendingactions/${id}/`)
|
||||
return data
|
||||
const { data } = await axios.delete(`${baseUrl}/pendingactions/${id}/`);
|
||||
return data;
|
||||
}
|
||||
|
@@ -1,62 +1,67 @@
|
||||
import axios from "axios"
|
||||
import axios from "axios";
|
||||
|
||||
const baseUrl = "/scripts"
|
||||
const baseUrl = "/scripts";
|
||||
|
||||
// script operations
|
||||
export async function fetchScripts(params = {}) {
|
||||
const { data } = await axios.get(`${baseUrl}/`, { params: params })
|
||||
return data
|
||||
const { data } = await axios.get(`${baseUrl}/`, { params: params });
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function testScript(agent_id, payload) {
|
||||
const { data } = await axios.post(`${baseUrl}/${agent_id}/test/`, payload)
|
||||
return data
|
||||
const { data } = await axios.post(`${baseUrl}/${agent_id}/test/`, payload);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function saveScript(payload) {
|
||||
const { data } = await axios.post(`${baseUrl}/`, payload)
|
||||
return data
|
||||
const { data } = await axios.post(`${baseUrl}/`, payload);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function editScript(payload) {
|
||||
const { data } = await axios.put(`${baseUrl}/${payload.id}/`, payload)
|
||||
return data
|
||||
const { data } = await axios.put(`${baseUrl}/${payload.id}/`, payload);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function removeScript(id) {
|
||||
const { data } = await axios.delete(`${baseUrl}/${id}/`)
|
||||
return data
|
||||
const { data } = await axios.delete(`${baseUrl}/${id}/`);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function downloadScript(id, params = {}) {
|
||||
const { data } = await axios.get(`${baseUrl}/${id}/download/`, { params: params })
|
||||
return data
|
||||
const { data } = await axios.get(`${baseUrl}/${id}/download/`, {
|
||||
params: params,
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
// script snippet operations
|
||||
export async function fetchScriptSnippets(params = {}) {
|
||||
const { data } = await axios.get(`${baseUrl}/snippets/`, { params: params })
|
||||
return data
|
||||
|
||||
const { data } = await axios.get(`${baseUrl}/snippets/`, { params: params });
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function saveScriptSnippet(payload) {
|
||||
const { data } = await axios.post(`${baseUrl}/snippets/`, payload)
|
||||
return data
|
||||
const { data } = await axios.post(`${baseUrl}/snippets/`, payload);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function fetchScriptSnippet(id, params = {}) {
|
||||
const { data } = await axios.get(`${baseUrl}/snippets/${id}/`, { params: params })
|
||||
return data
|
||||
const { data } = await axios.get(`${baseUrl}/snippets/${id}/`, {
|
||||
params: params,
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function editScriptSnippet(payload) {
|
||||
const { data } = await axios.put(`${baseUrl}/snippets/${payload.id}/`, payload)
|
||||
return data
|
||||
const { data } = await axios.put(
|
||||
`${baseUrl}/snippets/${payload.id}/`,
|
||||
payload
|
||||
);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function removeScriptSnippet(id) {
|
||||
const { data } = await axios.delete(`${baseUrl}/snippets/${id}/`)
|
||||
return data
|
||||
const { data } = await axios.delete(`${baseUrl}/snippets/${id}/`);
|
||||
return data;
|
||||
}
|
@@ -1,31 +1,41 @@
|
||||
import axios from "axios"
|
||||
import axios from "axios";
|
||||
|
||||
const baseUrl = "/services"
|
||||
const baseUrl = "/services";
|
||||
|
||||
export async function getAgentServices(agent_id, params = {}) {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/${agent_id}/`, { params: params })
|
||||
return data
|
||||
const { data } = await axios.get(`${baseUrl}/${agent_id}/`, {
|
||||
params: params,
|
||||
});
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function getAgentServiceDetails(agent_id, svcname, params = {}) {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/${agent_id}/${svcname}/`, { params: params })
|
||||
return data
|
||||
const { data } = await axios.get(`${baseUrl}/${agent_id}/${svcname}/`, {
|
||||
params: params,
|
||||
});
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function editAgentServiceStartType(agent_id, svcname, payload) {
|
||||
const { data } = await axios.put(`${baseUrl}/${agent_id}/${svcname}/`, payload)
|
||||
return data
|
||||
const { data } = await axios.put(
|
||||
`${baseUrl}/${agent_id}/${svcname}/`,
|
||||
payload
|
||||
);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function sendAgentServiceAction(agent_id, svcname, payload) {
|
||||
const { data } = await axios.post(`${baseUrl}/${agent_id}/${svcname}/`, payload)
|
||||
return data
|
||||
const { data } = await axios.post(
|
||||
`${baseUrl}/${agent_id}/${svcname}/`,
|
||||
payload
|
||||
);
|
||||
return data;
|
||||
}
|
||||
|
@@ -1,35 +1,37 @@
|
||||
import axios from "axios"
|
||||
import axios from "axios";
|
||||
|
||||
const baseUrl = "/software"
|
||||
const baseUrl = "/software";
|
||||
|
||||
export async function fetchChocosSoftware(params = {}) {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/chocos/`, { params: params })
|
||||
return data
|
||||
const { data } = await axios.get(`${baseUrl}/chocos/`, { params: params });
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function fetchAgentSoftware(agent_id, params = {}) {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/${agent_id}/`, { params: params })
|
||||
return data.software
|
||||
const { data } = await axios.get(`${baseUrl}/${agent_id}/`, {
|
||||
params: params,
|
||||
});
|
||||
return data.software;
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function installAgentSoftware(agent_id, payload) {
|
||||
const { data } = await axios.post(`${baseUrl}/${agent_id}/`, payload)
|
||||
return data
|
||||
const { data } = await axios.post(`${baseUrl}/${agent_id}/`, payload);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function refreshAgentSoftware(agent_id) {
|
||||
try {
|
||||
const { data } = await axios.put(`${baseUrl}/${agent_id}/`)
|
||||
return data
|
||||
const { data } = await axios.put(`${baseUrl}/${agent_id}/`);
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
console.error(e);
|
||||
}
|
||||
}
|
@@ -1,32 +1,32 @@
|
||||
import axios from "axios"
|
||||
import axios from "axios";
|
||||
|
||||
const baseUrl = "/tasks"
|
||||
const baseUrl = "/tasks";
|
||||
|
||||
export async function fetchTasks(params = {}) {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/`, { params: params })
|
||||
return data
|
||||
const { data } = await axios.get(`${baseUrl}/`, { params: params });
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function saveTask(payload) {
|
||||
const { data } = await axios.post(`${baseUrl}/`, payload)
|
||||
return data
|
||||
const { data } = await axios.post(`${baseUrl}/`, payload);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function updateTask(id, payload) {
|
||||
const { data } = await axios.put(`${baseUrl}/${id}/`, payload)
|
||||
return data
|
||||
const { data } = await axios.put(`${baseUrl}/${id}/`, payload);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function removeTask(id) {
|
||||
const { data } = await axios.delete(`${baseUrl}/${id}/`)
|
||||
return data
|
||||
const { data } = await axios.delete(`${baseUrl}/${id}/`);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function runTask(id, payload) {
|
||||
const { data } = await axios.post(`${baseUrl}/${id}/run/`, payload)
|
||||
return data
|
||||
const { data } = await axios.post(`${baseUrl}/${id}/run/`, payload);
|
||||
return data;
|
||||
}
|
||||
|
@@ -1,26 +1,30 @@
|
||||
import axios from "axios"
|
||||
import axios from "axios";
|
||||
|
||||
const baseUrl = "/winupdate"
|
||||
const baseUrl = "/winupdate";
|
||||
|
||||
// win updates api functions
|
||||
export async function fetchAgentUpdates(agent_id, params = {}) {
|
||||
try {
|
||||
const { data } = await axios.get(`${baseUrl}/${agent_id}/`, { params: params })
|
||||
return data
|
||||
} catch (e) { console.error(e) }
|
||||
const { data } = await axios.get(`${baseUrl}/${agent_id}/`, {
|
||||
params: params,
|
||||
});
|
||||
return data;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function runAgentUpdateScan(agent_id) {
|
||||
const { data } = await axios.post(`${baseUrl}/${agent_id}/scan/`)
|
||||
return data
|
||||
const { data } = await axios.post(`${baseUrl}/${agent_id}/scan/`);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function runAgentUpdateInstall(agent_id) {
|
||||
const { data } = await axios.post(`${baseUrl}/${agent_id}/install/`)
|
||||
return data
|
||||
const { data } = await axios.post(`${baseUrl}/${agent_id}/install/`);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function editAgentUpdate(id, payload) {
|
||||
const { data } = await axios.put(`${baseUrl}/${id}/`, payload)
|
||||
return data
|
||||
const { data } = await axios.put(`${baseUrl}/${id}/`, payload);
|
||||
return data;
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import axios from 'axios';
|
||||
import { Notify } from "quasar"
|
||||
import axios from "axios";
|
||||
import { Notify } from "quasar";
|
||||
|
||||
export const getBaseUrl = () => {
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
@@ -14,12 +14,11 @@ export const getBaseUrl = () => {
|
||||
};
|
||||
|
||||
export default function ({ app, router, store }) {
|
||||
|
||||
app.config.globalProperties.$axios = axios;
|
||||
|
||||
axios.interceptors.request.use(
|
||||
function (config) {
|
||||
config.baseURL = getBaseUrl()
|
||||
config.baseURL = getBaseUrl();
|
||||
const token = store.state.token;
|
||||
if (token != null) {
|
||||
config.headers.Authorization = `Token ${token}`;
|
||||
@@ -36,10 +35,10 @@ export default function ({ app, router, store }) {
|
||||
return response;
|
||||
},
|
||||
async function (error) {
|
||||
let text
|
||||
let text;
|
||||
|
||||
if (!error.response) {
|
||||
text = error.message
|
||||
text = error.message;
|
||||
}
|
||||
// unauthorized
|
||||
else if (error.response.status === 401) {
|
||||
@@ -48,25 +47,22 @@ export default function ({ app, router, store }) {
|
||||
// perms
|
||||
else if (error.response.status === 403) {
|
||||
// don't notify user if method is GET
|
||||
if (error.config.method === "get" || error.config.method === "patch") return Promise.reject({ ...error });
|
||||
if (error.config.method === "get" || error.config.method === "patch")
|
||||
return Promise.reject({ ...error });
|
||||
text = error.response.data.detail;
|
||||
}
|
||||
// catch all for other 400 error messages
|
||||
else if (error.response.status >= 400 && error.response.status < 500) {
|
||||
|
||||
if (error.config.responseType === "blob") {
|
||||
text = (await error.response.data.text()).replace(/^"|"$/g, '')
|
||||
}
|
||||
|
||||
else if (error.response.data.non_field_errors) {
|
||||
text = error.response.data.non_field_errors[0]
|
||||
|
||||
text = (await error.response.data.text()).replace(/^"|"$/g, "");
|
||||
} else if (error.response.data.non_field_errors) {
|
||||
text = error.response.data.non_field_errors[0];
|
||||
} else {
|
||||
if (typeof error.response.data === "string") {
|
||||
text = error.response.data
|
||||
text = error.response.data;
|
||||
} else if (typeof error.response.data === "object") {
|
||||
let [key, value] = Object.entries(error.response.data)[0]
|
||||
text = key + ": " + value[0]
|
||||
let [key, value] = Object.entries(error.response.data)[0];
|
||||
text = key + ": " + value[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -75,13 +71,14 @@ export default function ({ app, router, store }) {
|
||||
Notify.create({
|
||||
color: "negative",
|
||||
message: text ? text : "",
|
||||
caption: error.response ? error.response.status + ": " + error.response.statusText : "",
|
||||
timeout: 2500
|
||||
})
|
||||
caption: error.response
|
||||
? error.response.status + ": " + error.response.statusText
|
||||
: "",
|
||||
timeout: 2500,
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.reject({ ...error });
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -2,7 +2,15 @@
|
||||
<div style="width: 900px; max-width: 90vw">
|
||||
<q-card>
|
||||
<q-bar>
|
||||
<q-btn ref="refresh" @click="getUsers" class="q-mr-sm" dense flat push icon="refresh" />User Administration
|
||||
<q-btn
|
||||
ref="refresh"
|
||||
@click="getUsers"
|
||||
class="q-mr-sm"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
icon="refresh"
|
||||
/>User Administration
|
||||
<q-space />
|
||||
<q-btn dense flat icon="close" v-close-popup>
|
||||
<q-tooltip class="bg-white text-primary">Close</q-tooltip>
|
||||
@@ -10,7 +18,17 @@
|
||||
</q-bar>
|
||||
<div class="q-pa-md">
|
||||
<div class="q-gutter-sm">
|
||||
<q-btn ref="new" label="New" dense flat push unelevated no-caps icon="add" @click="showAddUserModal" />
|
||||
<q-btn
|
||||
ref="new"
|
||||
label="New"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
unelevated
|
||||
no-caps
|
||||
icon="add"
|
||||
@click="showAddUserModal"
|
||||
/>
|
||||
</div>
|
||||
<q-table
|
||||
dense
|
||||
@@ -40,11 +58,19 @@
|
||||
|
||||
<!-- body slots -->
|
||||
<template v-slot:body="props">
|
||||
<q-tr :props="props" class="cursor-pointer" @dblclick="showEditUserModal(props.row)">
|
||||
<q-tr
|
||||
:props="props"
|
||||
class="cursor-pointer"
|
||||
@dblclick="showEditUserModal(props.row)"
|
||||
>
|
||||
<!-- context menu -->
|
||||
<q-menu context-menu>
|
||||
<q-list dense style="min-width: 200px">
|
||||
<q-item clickable v-close-popup @click="showEditUserModal(props.row)">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showEditUserModal(props.row)"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="edit" />
|
||||
</q-item-section>
|
||||
@@ -64,14 +90,24 @@
|
||||
|
||||
<q-separator></q-separator>
|
||||
|
||||
<q-item clickable v-close-popup @click="ResetPassword(props.row)" id="context-reset">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="ResetPassword(props.row)"
|
||||
id="context-reset"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="autorenew" />
|
||||
</q-item-section>
|
||||
<q-item-section>Reset Password</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-item clickable v-close-popup @click="reset2FA(props.row)" id="context-reset">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="reset2FA(props.row)"
|
||||
id="context-reset"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="autorenew" />
|
||||
</q-item-section>
|
||||
@@ -97,7 +133,9 @@
|
||||
<q-td>{{ props.row.username }}</q-td>
|
||||
<q-td>{{ props.row.first_name }} {{ props.row.last_name }}</q-td>
|
||||
<q-td>{{ props.row.email }}</q-td>
|
||||
<q-td v-if="props.row.last_login">{{ formatDate(props.row.last_login) }}</q-td>
|
||||
<q-td v-if="props.row.last_login">{{
|
||||
formatDate(props.row.last_login)
|
||||
}}</q-td>
|
||||
<q-td v-else>Never</q-td>
|
||||
<q-td>{{ props.row.last_login_ip }}</q-td>
|
||||
</q-tr>
|
||||
@@ -118,7 +156,7 @@ import UserResetPasswordForm from "@/components/modals/admin/UserResetPasswordFo
|
||||
export default {
|
||||
name: "AdminManager",
|
||||
mixins: [mixins],
|
||||
setup(props) {
|
||||
setup() {
|
||||
// setup vuex
|
||||
const store = useStore();
|
||||
const formatDate = computed(() => store.getters.formatDate);
|
||||
@@ -131,8 +169,19 @@ export default {
|
||||
return {
|
||||
users: [],
|
||||
columns: [
|
||||
{ name: "is_active", label: "Active", field: "is_active", align: "left" },
|
||||
{ name: "username", label: "Username", field: "username", align: "left", sortable: true },
|
||||
{
|
||||
name: "is_active",
|
||||
label: "Active",
|
||||
field: "is_active",
|
||||
align: "left",
|
||||
},
|
||||
{
|
||||
name: "username",
|
||||
label: "Username",
|
||||
field: "username",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "name",
|
||||
label: "Name",
|
||||
@@ -174,7 +223,7 @@ export default {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.get("/accounts/users/")
|
||||
.then(r => {
|
||||
.then((r) => {
|
||||
this.users = r.data;
|
||||
this.$q.loading.hide();
|
||||
})
|
||||
@@ -190,13 +239,10 @@ export default {
|
||||
ok: { label: "Delete", color: "negative" },
|
||||
})
|
||||
.onOk(() => {
|
||||
this.$axios
|
||||
.delete(`/accounts/${user.id}/users/`)
|
||||
.then(() => {
|
||||
this.$axios.delete(`/accounts/${user.id}/users/`).then(() => {
|
||||
this.getUsers();
|
||||
this.notifySuccess(`User ${user.username} was deleted!`);
|
||||
})
|
||||
.catch(e => {});
|
||||
});
|
||||
});
|
||||
},
|
||||
showEditUserModal(user) {
|
||||
@@ -224,19 +270,18 @@ export default {
|
||||
if (user.username === this.logged_in_user) {
|
||||
return;
|
||||
}
|
||||
let text = !user.is_active ? "User enabled successfully" : "User disabled successfully";
|
||||
let text = !user.is_active
|
||||
? "User enabled successfully"
|
||||
: "User disabled successfully";
|
||||
|
||||
const data = {
|
||||
id: user.id,
|
||||
is_active: !user.is_active,
|
||||
};
|
||||
|
||||
this.$axios
|
||||
.put(`/accounts/${data.id}/users/`, data)
|
||||
.then(() => {
|
||||
this.$axios.put(`/accounts/${data.id}/users/`, data).then(() => {
|
||||
this.notifySuccess(text);
|
||||
})
|
||||
.catch(e => {});
|
||||
});
|
||||
},
|
||||
ResetPassword(user) {
|
||||
this.$q
|
||||
@@ -262,7 +307,9 @@ export default {
|
||||
ok: { label: "Reset", color: "positive" },
|
||||
})
|
||||
.onOk(() => {
|
||||
this.$axios.put("/accounts/users/reset_totp/", data).then(response => {
|
||||
this.$axios
|
||||
.put("/accounts/users/reset_totp/", data)
|
||||
.then((response) => {
|
||||
this.notifySuccess(response.data, 4000);
|
||||
});
|
||||
});
|
||||
@@ -270,7 +317,7 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
logged_in_user: state => state.username,
|
||||
logged_in_user: (state) => state.username,
|
||||
}),
|
||||
},
|
||||
mounted() {
|
||||
|
@@ -2,7 +2,10 @@
|
||||
<div class="q-pa-none">
|
||||
<q-table
|
||||
dense
|
||||
:table-class="{ 'table-bgcolor': !$q.dark.isActive, 'table-bgcolor-dark': $q.dark.isActive }"
|
||||
:table-class="{
|
||||
'table-bgcolor': !$q.dark.isActive,
|
||||
'table-bgcolor-dark': $q.dark.isActive,
|
||||
}"
|
||||
class="agents-tbl-sticky"
|
||||
:table-style="{ 'max-height': tableHeight }"
|
||||
:rows="agents"
|
||||
@@ -92,18 +95,26 @@
|
||||
</q-menu>
|
||||
<q-td>
|
||||
<q-checkbox
|
||||
v-if="props.row.alert_template && props.row.alert_template.always_text !== null"
|
||||
v-if="
|
||||
props.row.alert_template &&
|
||||
props.row.alert_template.always_text !== null
|
||||
"
|
||||
v-model="props.row.alert_template.always_text"
|
||||
disable
|
||||
dense
|
||||
>
|
||||
<q-tooltip> Setting is overridden by alert template: {{ props.row.alert_template.name }} </q-tooltip>
|
||||
<q-tooltip>
|
||||
Setting is overridden by alert template:
|
||||
{{ props.row.alert_template.name }}
|
||||
</q-tooltip>
|
||||
</q-checkbox>
|
||||
|
||||
<q-checkbox
|
||||
v-else
|
||||
dense
|
||||
@update:model-value="overdueAlert('text', props.row, props.row.overdue_text_alert)"
|
||||
@update:model-value="
|
||||
overdueAlert('text', props.row, props.row.overdue_text_alert)
|
||||
"
|
||||
v-model="props.row.overdue_text_alert"
|
||||
>
|
||||
<q-tooltip>{{ sms_overdue_text }}</q-tooltip>
|
||||
@@ -111,18 +122,26 @@
|
||||
</q-td>
|
||||
<q-td>
|
||||
<q-checkbox
|
||||
v-if="props.row.alert_template && props.row.alert_template.always_email !== null"
|
||||
v-if="
|
||||
props.row.alert_template &&
|
||||
props.row.alert_template.always_email !== null
|
||||
"
|
||||
v-model="props.row.alert_template.always_email"
|
||||
disable
|
||||
dense
|
||||
>
|
||||
<q-tooltip> Setting is overridden by alert template: {{ props.row.alert_template.name }} </q-tooltip>
|
||||
<q-tooltip>
|
||||
Setting is overridden by alert template:
|
||||
{{ props.row.alert_template.name }}
|
||||
</q-tooltip>
|
||||
</q-checkbox>
|
||||
|
||||
<q-checkbox
|
||||
v-else
|
||||
dense
|
||||
@update:model-value="overdueAlert('email', props.row, props.row.overdue_email_alert)"
|
||||
@update:model-value="
|
||||
overdueAlert('email', props.row, props.row.overdue_email_alert)
|
||||
"
|
||||
v-model="props.row.overdue_email_alert"
|
||||
>
|
||||
<q-tooltip>{{ email_overdue_text }}</q-tooltip>
|
||||
@@ -130,18 +149,30 @@
|
||||
</q-td>
|
||||
<q-td>
|
||||
<q-checkbox
|
||||
v-if="props.row.alert_template && props.row.alert_template.always_alert !== null"
|
||||
v-if="
|
||||
props.row.alert_template &&
|
||||
props.row.alert_template.always_alert !== null
|
||||
"
|
||||
v-model="props.row.alert_template.always_alert"
|
||||
disable
|
||||
dense
|
||||
>
|
||||
<q-tooltip> Setting is overridden by alert template: {{ props.row.alert_template.name }} </q-tooltip>
|
||||
<q-tooltip>
|
||||
Setting is overridden by alert template:
|
||||
{{ props.row.alert_template.name }}
|
||||
</q-tooltip>
|
||||
</q-checkbox>
|
||||
|
||||
<q-checkbox
|
||||
v-else
|
||||
dense
|
||||
@update:model-value="overdueAlert('dashboard', props.row, props.row.overdue_dashboard_alert)"
|
||||
@update:model-value="
|
||||
overdueAlert(
|
||||
'dashboard',
|
||||
props.row,
|
||||
props.row.overdue_dashboard_alert
|
||||
)
|
||||
"
|
||||
v-model="props.row.overdue_dashboard_alert"
|
||||
>
|
||||
<q-tooltip>{{ dashboard_overdue_text }}</q-tooltip>
|
||||
@@ -149,42 +180,88 @@
|
||||
</q-td>
|
||||
|
||||
<q-td key="plat" :props="props">
|
||||
<q-icon v-if="props.row.plat === 'windows'" name="mdi-microsoft-windows" size="sm" color="primary">
|
||||
<q-icon
|
||||
v-if="props.row.plat === 'windows'"
|
||||
name="mdi-microsoft-windows"
|
||||
size="sm"
|
||||
color="primary"
|
||||
>
|
||||
<q-tooltip>Microsoft Windows</q-tooltip>
|
||||
</q-icon>
|
||||
<q-icon v-else-if="props.row.plat === 'linux'" name="mdi-linux" size="sm" color="primary">
|
||||
<q-icon
|
||||
v-else-if="props.row.plat === 'linux'"
|
||||
name="mdi-linux"
|
||||
size="sm"
|
||||
color="primary"
|
||||
>
|
||||
<q-tooltip>Linux</q-tooltip>
|
||||
</q-icon>
|
||||
</q-td>
|
||||
|
||||
<q-td key="checks-status" :props="props">
|
||||
<q-icon v-if="props.row.maintenance_mode" name="construction" size="1.2em" color="green">
|
||||
<q-icon
|
||||
v-if="props.row.maintenance_mode"
|
||||
name="construction"
|
||||
size="1.2em"
|
||||
color="green"
|
||||
>
|
||||
<q-tooltip>Maintenance Mode Enabled</q-tooltip>
|
||||
</q-icon>
|
||||
<q-icon v-else-if="props.row.checks.failing > 0" name="fas fa-check-double" size="1.2em" color="negative">
|
||||
<q-icon
|
||||
v-else-if="props.row.checks.failing > 0"
|
||||
name="fas fa-check-double"
|
||||
size="1.2em"
|
||||
color="negative"
|
||||
>
|
||||
<q-tooltip>Checks failing</q-tooltip>
|
||||
</q-icon>
|
||||
<q-icon v-else-if="props.row.checks.warning > 0" name="fas fa-check-double" size="1.2em" color="warning">
|
||||
<q-icon
|
||||
v-else-if="props.row.checks.warning > 0"
|
||||
name="fas fa-check-double"
|
||||
size="1.2em"
|
||||
color="warning"
|
||||
>
|
||||
<q-tooltip>Checks warning</q-tooltip>
|
||||
</q-icon>
|
||||
<q-icon v-else-if="props.row.checks.info > 0" name="fas fa-check-double" size="1.2em" color="info">
|
||||
<q-icon
|
||||
v-else-if="props.row.checks.info > 0"
|
||||
name="fas fa-check-double"
|
||||
size="1.2em"
|
||||
color="info"
|
||||
>
|
||||
<q-tooltip>Checks info</q-tooltip>
|
||||
</q-icon>
|
||||
<q-icon v-else name="fas fa-check-double" size="1.2em" color="positive">
|
||||
<q-icon
|
||||
v-else
|
||||
name="fas fa-check-double"
|
||||
size="1.2em"
|
||||
color="positive"
|
||||
>
|
||||
<q-tooltip>Checks passing</q-tooltip>
|
||||
</q-icon>
|
||||
</q-td>
|
||||
|
||||
<q-td key="client_name" :props="props">{{ props.row.client_name }}</q-td>
|
||||
<q-td key="client_name" :props="props">{{
|
||||
props.row.client_name
|
||||
}}</q-td>
|
||||
<q-td key="site_name" :props="props">{{ props.row.site_name }}</q-td>
|
||||
<q-td key="hostname" :props="props">{{ props.row.hostname }}</q-td>
|
||||
<q-td key="description" :props="props">{{ props.row.description }}</q-td>
|
||||
<q-td key="description" :props="props">{{
|
||||
props.row.description
|
||||
}}</q-td>
|
||||
<q-td key="user" :props="props">
|
||||
<span class="text-italic" v-if="props.row.italic">{{ props.row.logged_username }}</span>
|
||||
<span class="text-italic" v-if="props.row.italic">{{
|
||||
props.row.logged_username
|
||||
}}</span>
|
||||
<span v-else>{{ props.row.logged_username }}</span>
|
||||
</q-td>
|
||||
<q-td :props="props" key="patchespending">
|
||||
<q-icon v-if="props.row.has_patches_pending" name="verified_user" size="1.5em" color="primary">
|
||||
<q-icon
|
||||
v-if="props.row.has_patches_pending"
|
||||
name="verified_user"
|
||||
size="1.5em"
|
||||
color="primary"
|
||||
>
|
||||
<q-tooltip>Patches Pending</q-tooltip>
|
||||
</q-icon>
|
||||
</q-td>
|
||||
@@ -197,28 +274,49 @@
|
||||
color="warning"
|
||||
class="cursor-pointer"
|
||||
>
|
||||
<q-tooltip>Pending Action Count: {{ props.row.pending_actions_count }}</q-tooltip>
|
||||
<q-tooltip
|
||||
>Pending Action Count:
|
||||
{{ props.row.pending_actions_count }}</q-tooltip
|
||||
>
|
||||
</q-icon>
|
||||
</q-td>
|
||||
<!-- needs reboot -->
|
||||
<q-td key="needsreboot">
|
||||
<q-icon v-if="props.row.needs_reboot" name="fas fa-power-off" color="primary">
|
||||
<q-icon
|
||||
v-if="props.row.needs_reboot"
|
||||
name="fas fa-power-off"
|
||||
color="primary"
|
||||
>
|
||||
<q-tooltip>Reboot required</q-tooltip>
|
||||
</q-icon>
|
||||
</q-td>
|
||||
<q-td key="agentstatus">
|
||||
<q-icon v-if="props.row.status === 'overdue'" name="fas fa-signal" size="1.2em" color="negative">
|
||||
<q-icon
|
||||
v-if="props.row.status === 'overdue'"
|
||||
name="fas fa-signal"
|
||||
size="1.2em"
|
||||
color="negative"
|
||||
>
|
||||
<q-tooltip>Agent overdue</q-tooltip>
|
||||
</q-icon>
|
||||
<q-icon v-else-if="props.row.status === 'offline'" name="fas fa-signal" size="1.2em" color="warning">
|
||||
<q-icon
|
||||
v-else-if="props.row.status === 'offline'"
|
||||
name="fas fa-signal"
|
||||
size="1.2em"
|
||||
color="warning"
|
||||
>
|
||||
<q-tooltip>Agent offline</q-tooltip>
|
||||
</q-icon>
|
||||
<q-icon v-else name="fas fa-signal" size="1.2em" color="positive">
|
||||
<q-tooltip>Agent online</q-tooltip>
|
||||
</q-icon>
|
||||
</q-td>
|
||||
<q-td key="last_seen" :props="props">{{ formatDate(props.row.last_seen) }}</q-td>
|
||||
<q-td key="boot_time" :props="props">{{ bootTime(props.row.boot_time) }}</q-td>
|
||||
<q-td key="last_seen" :props="props">{{
|
||||
formatDate(props.row.last_seen)
|
||||
}}</q-td>
|
||||
<q-td key="boot_time" :props="props">{{
|
||||
bootTime(props.row.boot_time)
|
||||
}}</q-td>
|
||||
</q-tr>
|
||||
</template>
|
||||
</q-table>
|
||||
@@ -269,7 +367,7 @@ export default {
|
||||
|
||||
const params = lowerTerms.trim().split(" ");
|
||||
// parse search text and set variables
|
||||
params.forEach(param => {
|
||||
params.forEach((param) => {
|
||||
if (param.includes("is:")) {
|
||||
advancedFilter = true;
|
||||
let filter = param.split(":")[1];
|
||||
@@ -277,22 +375,30 @@ export default {
|
||||
if (filter === "actionspending") actions = true;
|
||||
else if (filter === "checksfailing") checks = true;
|
||||
else if (filter === "rebootneeded") reboot = true;
|
||||
else if (filter === "online" || filter === "offline" || filter === "expired" || filter === "overdue")
|
||||
else if (
|
||||
filter === "online" ||
|
||||
filter === "offline" ||
|
||||
filter === "expired" ||
|
||||
filter === "overdue"
|
||||
)
|
||||
availability = filter;
|
||||
} else {
|
||||
search = param + "";
|
||||
}
|
||||
});
|
||||
|
||||
return rows.filter(row => {
|
||||
return rows.filter((row) => {
|
||||
if (advancedFilter) {
|
||||
if (checks && !row.checks.has_failing_checks) return false;
|
||||
if (patches && !row.has_patches_pending) return false;
|
||||
if (actions && row.pending_actions_count === 0) return false;
|
||||
if (reboot && !row.needs_reboot) return false;
|
||||
if (availability === "online" && row.status !== "online") return false;
|
||||
else if (availability === "offline" && row.status !== "offline") return false;
|
||||
else if (availability === "overdue" && row.status !== "overdue") return false;
|
||||
if (availability === "online" && row.status !== "online")
|
||||
return false;
|
||||
else if (availability === "offline" && row.status !== "offline")
|
||||
return false;
|
||||
else if (availability === "overdue" && row.status !== "overdue")
|
||||
return false;
|
||||
else if (availability === "expired") {
|
||||
let now = new Date();
|
||||
let lastSeen = date.extractDate(row.last_seen, "MM DD YYYY HH:mm");
|
||||
@@ -302,9 +408,10 @@ export default {
|
||||
}
|
||||
|
||||
// Normal text filter
|
||||
return cols.some(col => {
|
||||
return cols.some((col) => {
|
||||
const val = cellValue(col, row) + "";
|
||||
const haystack = val === "undefined" || val === "null" ? "" : val.toLowerCase();
|
||||
const haystack =
|
||||
val === "undefined" || val === "null" ? "" : val.toLowerCase();
|
||||
return haystack.indexOf(search) !== -1;
|
||||
});
|
||||
});
|
||||
@@ -354,18 +461,17 @@ export default {
|
||||
[db_field]: !alert_action,
|
||||
};
|
||||
const alertColor = !alert_action ? "positive" : "info";
|
||||
this.$axios
|
||||
.put(`/agents/${agent.agent_id}/`, data)
|
||||
.then(r => {
|
||||
this.$axios.put(`/agents/${agent.agent_id}/`, data).then(() => {
|
||||
this.$q.notify({
|
||||
color: alertColor,
|
||||
textColor: "black",
|
||||
icon: "fas fa-check-circle",
|
||||
message: `${capitalize(category)} alerts will now be ${action} when ${agent.hostname} is overdue.`,
|
||||
message: `${capitalize(category)} alerts will now be ${action} when ${
|
||||
agent.hostname
|
||||
} is overdue.`,
|
||||
timeout: 5000,
|
||||
});
|
||||
})
|
||||
.catch(e => {});
|
||||
});
|
||||
},
|
||||
agentClass(status) {
|
||||
if (status === "offline") {
|
||||
@@ -417,4 +523,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@@ -1,6 +1,8 @@
|
||||
<template>
|
||||
<q-btn dense flat icon="notifications">
|
||||
<q-badge v-if="alertsCount > 0" :color="badgeColor" floating transparent>{{ alertsCountText() }}</q-badge>
|
||||
<q-badge v-if="alertsCount > 0" :color="badgeColor" floating transparent>{{
|
||||
alertsCountText()
|
||||
}}</q-badge>
|
||||
<q-menu style="max-height: 30vh">
|
||||
<q-list separator>
|
||||
<q-item v-if="alertsCount === 0">No New Alerts</q-item>
|
||||
@@ -8,28 +10,49 @@
|
||||
<q-item-section>
|
||||
<q-item-label overline
|
||||
><router-link :to="`/agents/${alert.agent_id}`"
|
||||
>{{ alert.client }} - {{ alert.site }} - {{ alert.hostname }}</router-link
|
||||
>{{ alert.client }} - {{ alert.site }} -
|
||||
{{ alert.hostname }}</router-link
|
||||
></q-item-label
|
||||
>
|
||||
<q-item-label lines="1">
|
||||
<q-icon size="xs" :class="`text-${alertIconColor(alert.severity)}`" :name="alert.severity"></q-icon>
|
||||
<q-icon
|
||||
size="xs"
|
||||
:class="`text-${alertIconColor(alert.severity)}`"
|
||||
:name="alert.severity"
|
||||
></q-icon>
|
||||
{{ alert.message }}
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
|
||||
<q-item-section side top>
|
||||
<q-item-label caption>{{ getTimeLapse(alert.alert_time) }}</q-item-label>
|
||||
<q-item-label caption>{{
|
||||
getTimeLapse(alert.alert_time)
|
||||
}}</q-item-label>
|
||||
<q-item-label>
|
||||
<q-icon name="snooze" size="xs" class="cursor-pointer" @click="snoozeAlert(alert)" v-close-popup>
|
||||
<q-icon
|
||||
name="snooze"
|
||||
size="xs"
|
||||
class="cursor-pointer"
|
||||
@click="snoozeAlert(alert)"
|
||||
v-close-popup
|
||||
>
|
||||
<q-tooltip>Snooze alert</q-tooltip>
|
||||
</q-icon>
|
||||
<q-icon name="flag" size="xs" class="cursor-pointer" @click="resolveAlert(alert)" v-close-popup>
|
||||
<q-icon
|
||||
name="flag"
|
||||
size="xs"
|
||||
class="cursor-pointer"
|
||||
@click="resolveAlert(alert)"
|
||||
v-close-popup
|
||||
>
|
||||
<q-tooltip>Resolve alert</q-tooltip>
|
||||
</q-icon>
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable v-close-popup @click="showOverview">View All Alerts ({{ alertsCount }})</q-item>
|
||||
<q-item clickable v-close-popup @click="showOverview"
|
||||
>View All Alerts ({{ alertsCount }})</q-item
|
||||
>
|
||||
</q-list>
|
||||
</q-menu>
|
||||
</q-btn>
|
||||
@@ -43,7 +66,7 @@ import { getTimeLapse } from "@/utils/format";
|
||||
export default {
|
||||
name: "AlertsIcon",
|
||||
mixins: [mixins],
|
||||
setup(props) {
|
||||
setup() {
|
||||
return {
|
||||
getTimeLapse,
|
||||
};
|
||||
@@ -60,7 +83,7 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
badgeColor() {
|
||||
const severities = this.topAlerts.map(alert => alert.severity);
|
||||
const severities = this.topAlerts.map((alert) => alert.severity);
|
||||
|
||||
if (severities.includes("error")) return this.errorColor;
|
||||
else if (severities.includes("warning")) return this.warningColor;
|
||||
@@ -69,13 +92,10 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
getAlerts() {
|
||||
this.$axios
|
||||
.patch("alerts/", { top: 10 })
|
||||
.then(r => {
|
||||
this.$axios.patch("alerts/", { top: 10 }).then((r) => {
|
||||
this.alertsCount = r.data.alerts_count;
|
||||
this.topAlerts = r.data.alerts;
|
||||
})
|
||||
.catch(e => {});
|
||||
});
|
||||
},
|
||||
showOverview() {
|
||||
this.$q
|
||||
@@ -94,11 +114,11 @@ export default {
|
||||
prompt: {
|
||||
model: "",
|
||||
type: "number",
|
||||
isValid: val => !!val && val > 0 && val < 9999,
|
||||
isValid: (val) => !!val && val > 0 && val < 9999,
|
||||
},
|
||||
cancel: true,
|
||||
})
|
||||
.onOk(days => {
|
||||
.onOk((days) => {
|
||||
this.$q.loading.show();
|
||||
|
||||
const data = {
|
||||
@@ -109,12 +129,12 @@ export default {
|
||||
|
||||
this.$axios
|
||||
.put(`alerts/${alert.id}/`, data)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.getAlerts();
|
||||
this.$q.loading.hide();
|
||||
this.notifySuccess(`The alert has been snoozed for ${days} days`);
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
});
|
||||
@@ -129,12 +149,12 @@ export default {
|
||||
|
||||
this.$axios
|
||||
.put(`alerts/${alert.id}/`, data)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.getAlerts();
|
||||
this.$q.loading.hide();
|
||||
this.notifySuccess("The alert has been resolved");
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
|
@@ -3,7 +3,15 @@
|
||||
<div class="q-dialog-plugin" style="width: 90vw; max-width: 90vw">
|
||||
<q-card>
|
||||
<q-bar>
|
||||
<q-btn ref="refresh" @click="refresh" class="q-mr-sm" dense flat push icon="refresh" />Alerts Manager
|
||||
<q-btn
|
||||
ref="refresh"
|
||||
@click="refresh"
|
||||
class="q-mr-sm"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
icon="refresh"
|
||||
/>Alerts Manager
|
||||
<q-space />
|
||||
<q-btn dense flat icon="close" v-close-popup>
|
||||
<q-tooltip class="bg-white text-primary">Close</q-tooltip>
|
||||
@@ -11,7 +19,17 @@
|
||||
</q-bar>
|
||||
<div class="q-pa-sm" style="min-height: 65vh; max-height: 65vh">
|
||||
<div class="q-gutter-sm">
|
||||
<q-btn ref="new" label="New" dense flat push unelevated no-caps icon="add" @click="showAddTemplateModal" />
|
||||
<q-btn
|
||||
ref="new"
|
||||
label="New"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
unelevated
|
||||
no-caps
|
||||
icon="add"
|
||||
@click="showAddTemplateModal"
|
||||
/>
|
||||
</div>
|
||||
<q-table
|
||||
dense
|
||||
@@ -67,13 +85,21 @@
|
||||
<!-- context menu -->
|
||||
<q-menu context-menu>
|
||||
<q-list dense style="min-width: 200px">
|
||||
<q-item clickable v-close-popup @click="showEditTemplateModal(props.row)">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showEditTemplateModal(props.row)"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="edit" />
|
||||
</q-item-section>
|
||||
<q-item-section>Edit</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable v-close-popup @click="deleteTemplate(props.row)">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="deleteTemplate(props.row)"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="delete" />
|
||||
</q-item-section>
|
||||
@@ -82,7 +108,11 @@
|
||||
|
||||
<q-separator></q-separator>
|
||||
|
||||
<q-item clickable v-close-popup @click="showAlertExclusions(props.row)">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showAlertExclusions(props.row)"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="rule" />
|
||||
</q-item-section>
|
||||
@@ -98,30 +128,59 @@
|
||||
</q-menu>
|
||||
<!-- enabled checkbox -->
|
||||
<q-td>
|
||||
<q-checkbox dense @update:model-value="toggleEnabled(props.row)" v-model="props.row.is_active" />
|
||||
<q-checkbox
|
||||
dense
|
||||
@update:model-value="toggleEnabled(props.row)"
|
||||
v-model="props.row.is_active"
|
||||
/>
|
||||
</q-td>
|
||||
<!-- agent settings -->
|
||||
<q-td>
|
||||
<q-icon v-if="props.row.agent_settings" color="primary" name="done" size="sm">
|
||||
<q-tooltip>Alert template has agent alert settings</q-tooltip>
|
||||
<q-icon
|
||||
v-if="props.row.agent_settings"
|
||||
color="primary"
|
||||
name="done"
|
||||
size="sm"
|
||||
>
|
||||
<q-tooltip
|
||||
>Alert template has agent alert settings</q-tooltip
|
||||
>
|
||||
</q-icon>
|
||||
</q-td>
|
||||
<!-- text settings -->
|
||||
<q-td>
|
||||
<q-icon v-if="props.row.check_settings" color="primary" name="done" size="sm">
|
||||
<q-tooltip>Alert template has check alert settings</q-tooltip>
|
||||
<q-icon
|
||||
v-if="props.row.check_settings"
|
||||
color="primary"
|
||||
name="done"
|
||||
size="sm"
|
||||
>
|
||||
<q-tooltip
|
||||
>Alert template has check alert settings</q-tooltip
|
||||
>
|
||||
</q-icon>
|
||||
</q-td>
|
||||
<!-- dashboard settings -->
|
||||
<q-td>
|
||||
<q-icon v-if="props.row.task_settings" color="primary" name="done" size="sm">
|
||||
<q-tooltip>Alert template has task alert settings</q-tooltip>
|
||||
<q-icon
|
||||
v-if="props.row.task_settings"
|
||||
color="primary"
|
||||
name="done"
|
||||
size="sm"
|
||||
>
|
||||
<q-tooltip
|
||||
>Alert template has task alert settings</q-tooltip
|
||||
>
|
||||
</q-icon>
|
||||
</q-td>
|
||||
<!-- name -->
|
||||
<q-td
|
||||
>{{ props.row.name }}
|
||||
<q-chip v-if="props.row.default_template" color="primary" text-color="white" size="sm"
|
||||
<q-chip
|
||||
v-if="props.row.default_template"
|
||||
color="primary"
|
||||
text-color="white"
|
||||
size="sm"
|
||||
>Default</q-chip
|
||||
>
|
||||
</q-td>
|
||||
@@ -131,7 +190,9 @@
|
||||
style="cursor: pointer; text-decoration: underline"
|
||||
class="text-primary"
|
||||
@click="showTemplateApplied(props.row)"
|
||||
>Show where template is applied ({{ props.row.applied_count }})</span
|
||||
>Show where template is applied ({{
|
||||
props.row.applied_count
|
||||
}})</span
|
||||
></q-td
|
||||
>
|
||||
<!-- alert exclusions -->
|
||||
@@ -175,10 +236,27 @@ export default {
|
||||
selectedTemplate: null,
|
||||
templates: [],
|
||||
columns: [
|
||||
{ name: "is_active", label: "Active", field: "is_active", align: "left" },
|
||||
{ name: "agent_settings", label: "Agent Settings", field: "agent_settings" },
|
||||
{ name: "check_settings", label: "Check Settings", field: "check_settings" },
|
||||
{ name: "task_settings", label: "Task Settings", field: "task_settings" },
|
||||
{
|
||||
name: "is_active",
|
||||
label: "Active",
|
||||
field: "is_active",
|
||||
align: "left",
|
||||
},
|
||||
{
|
||||
name: "agent_settings",
|
||||
label: "Agent Settings",
|
||||
field: "agent_settings",
|
||||
},
|
||||
{
|
||||
name: "check_settings",
|
||||
label: "Check Settings",
|
||||
field: "check_settings",
|
||||
},
|
||||
{
|
||||
name: "task_settings",
|
||||
label: "Task Settings",
|
||||
field: "task_settings",
|
||||
},
|
||||
{ name: "name", label: "Name", field: "name", align: "left" },
|
||||
{
|
||||
name: "applied_to",
|
||||
@@ -217,11 +295,11 @@ export default {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.get("alerts/templates/")
|
||||
.then(r => {
|
||||
.then((r) => {
|
||||
this.templates = r.data;
|
||||
this.$q.loading.hide();
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
@@ -244,12 +322,14 @@ export default {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.delete(`alerts/templates/${template.id}/`)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.refresh();
|
||||
this.$q.loading.hide();
|
||||
this.notifySuccess(`Alert template ${template.name} was deleted!`);
|
||||
this.notifySuccess(
|
||||
`Alert template ${template.name} was deleted!`
|
||||
);
|
||||
})
|
||||
.catch(error => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
});
|
||||
@@ -297,23 +377,23 @@ export default {
|
||||
});
|
||||
},
|
||||
toggleEnabled(template) {
|
||||
let text = !template.is_active ? "Template enabled successfully" : "Template disabled successfully";
|
||||
let text = !template.is_active
|
||||
? "Template enabled successfully"
|
||||
: "Template disabled successfully";
|
||||
|
||||
const data = {
|
||||
id: template.id,
|
||||
is_active: !template.is_active,
|
||||
};
|
||||
|
||||
this.$axios
|
||||
.put(`alerts/templates/${template.id}/`, data)
|
||||
.then(r => {
|
||||
this.$axios.put(`alerts/templates/${template.id}/`, data).then(() => {
|
||||
this.notifySuccess(text);
|
||||
this.$store.dispatch("refreshDashboard");
|
||||
})
|
||||
.catch(error => {});
|
||||
});
|
||||
},
|
||||
rowSelectedClass(id, selectedTemplate) {
|
||||
if (selectedTemplate && selectedTemplate.id === id) return this.$q.dark.isActive ? "highlight-dark" : "highlight";
|
||||
if (selectedTemplate && selectedTemplate.id === id)
|
||||
return this.$q.dark.isActive ? "highlight-dark" : "highlight";
|
||||
},
|
||||
show() {
|
||||
this.$refs.dialog.show();
|
||||
|
@@ -51,7 +51,11 @@
|
||||
<q-item clickable v-close-popup @click="showDeployments">
|
||||
<q-item-section>Manage Deployments</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable v-close-popup @click="showUpdateAgentsModal = true">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showUpdateAgentsModal = true"
|
||||
>
|
||||
<q-item-section>Update Agents</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
@@ -87,11 +91,20 @@
|
||||
<q-item-section>User Administration</q-item-section>
|
||||
</q-item>
|
||||
<!-- core settings -->
|
||||
<q-item clickable v-close-popup @click="showEditCoreSettingsModal = true">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showEditCoreSettingsModal = true"
|
||||
>
|
||||
<q-item-section>Global Settings</q-item-section>
|
||||
</q-item>
|
||||
<!-- code sign -->
|
||||
<q-item v-if="!hosted" clickable v-close-popup @click="showCodeSign = true">
|
||||
<q-item
|
||||
v-if="!hosted"
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showCodeSign = true"
|
||||
>
|
||||
<q-item-section>Code Signing</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
@@ -102,7 +115,11 @@
|
||||
<q-menu auto-close>
|
||||
<q-list dense style="min-width: 100px">
|
||||
<!-- bulk command -->
|
||||
<q-item clickable v-close-popup @click="showBulkAction('command')">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showBulkAction('command')"
|
||||
>
|
||||
<q-item-section>Bulk Command</q-item-section>
|
||||
</q-item>
|
||||
<!-- bulk script -->
|
||||
@@ -114,7 +131,11 @@
|
||||
<q-item-section>Bulk Patch Management</q-item-section>
|
||||
</q-item>
|
||||
<!-- server maintenance -->
|
||||
<q-item clickable v-close-popup @click="showServerMaintenance = true">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showServerMaintenance = true"
|
||||
>
|
||||
<q-item-section>Server Maintenance</q-item-section>
|
||||
</q-item>
|
||||
<!-- clear cache -->
|
||||
@@ -160,7 +181,12 @@
|
||||
</div>
|
||||
<!-- Update Agents Modal -->
|
||||
<div class="q-pa-md q-gutter-sm">
|
||||
<q-dialog v-model="showUpdateAgentsModal" maximized transition-show="slide-up" transition-hide="slide-down">
|
||||
<q-dialog
|
||||
v-model="showUpdateAgentsModal"
|
||||
maximized
|
||||
transition-show="slide-up"
|
||||
transition-hide="slide-down"
|
||||
>
|
||||
<UpdateAgents @close="showUpdateAgentsModal = false" />
|
||||
</q-dialog>
|
||||
</div>
|
||||
@@ -199,7 +225,7 @@ import AdminManager from "@/components/AdminManager";
|
||||
import InstallAgent from "@/components/modals/agents/InstallAgent";
|
||||
import AuditManager from "@/components/logs/AuditManager";
|
||||
import BulkAction from "@/components/modals/agents/BulkAction";
|
||||
import Deployment from "@/components/clients/Deployment";
|
||||
import DeploymentTable from "@/components/clients/DeploymentTable";
|
||||
import ServerMaintenance from "@/components/modals/core/ServerMaintenance";
|
||||
import CodeSign from "@/components/modals/coresettings/CodeSign";
|
||||
import PermissionsManager from "@/components/accounts/PermissionsManager";
|
||||
@@ -214,7 +240,6 @@ export default {
|
||||
AdminManager,
|
||||
ServerMaintenance,
|
||||
CodeSign,
|
||||
PermissionsManager,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -235,8 +260,7 @@ export default {
|
||||
clearCache() {
|
||||
this.$axios
|
||||
.get("/core/clearcache/")
|
||||
.then(r => this.notifySuccess(r.data))
|
||||
.catch(() => {});
|
||||
.then((r) => this.notifySuccess(r.data));
|
||||
},
|
||||
openHelp(mode) {
|
||||
let url;
|
||||
@@ -248,10 +272,12 @@ export default {
|
||||
url = "https://docs.tacticalrmm.com";
|
||||
break;
|
||||
case "bug":
|
||||
url = "https://github.com/amidaware/tacticalrmm/issues/new?template=bug_report.md";
|
||||
url =
|
||||
"https://github.com/amidaware/tacticalrmm/issues/new?template=bug_report.md";
|
||||
break;
|
||||
case "feature":
|
||||
url = "https://github.com/amidaware/tacticalrmm/issues/new?template=feature_request.md";
|
||||
url =
|
||||
"https://github.com/amidaware/tacticalrmm/issues/new?template=feature_request.md";
|
||||
break;
|
||||
case "discord":
|
||||
url = "https://discord.gg/upGTkWp";
|
||||
@@ -349,7 +375,7 @@ export default {
|
||||
},
|
||||
showDeployments() {
|
||||
this.$q.dialog({
|
||||
component: Deployment,
|
||||
component: DeploymentTable,
|
||||
});
|
||||
},
|
||||
},
|
||||
|
@@ -1,6 +1,8 @@
|
||||
<template>
|
||||
<q-layout container view="hHh lpr lfr">
|
||||
<q-header :class="{ 'bg-dark': $q.dark.isActive, 'bg-light': !$q.dark.isActive }">
|
||||
<q-header
|
||||
:class="{ 'bg-dark': $q.dark.isActive, 'bg-light': !$q.dark.isActive }"
|
||||
>
|
||||
<q-tabs
|
||||
v-model="subtab"
|
||||
dense
|
||||
@@ -88,34 +90,74 @@
|
||||
</q-header>
|
||||
<q-page-container>
|
||||
<q-tab-panels v-model="subtab" :animated="false">
|
||||
<q-tab-panel v-if="activeTabs.includes('summary')" name="summary" class="q-pa-none">
|
||||
<q-tab-panel
|
||||
v-if="activeTabs.includes('summary')"
|
||||
name="summary"
|
||||
class="q-pa-none"
|
||||
>
|
||||
<SummaryTab />
|
||||
</q-tab-panel>
|
||||
<q-tab-panel v-if="activeTabs.includes('checks')" name="checks" class="q-pa-none">
|
||||
<q-tab-panel
|
||||
v-if="activeTabs.includes('checks')"
|
||||
name="checks"
|
||||
class="q-pa-none"
|
||||
>
|
||||
<ChecksTab />
|
||||
</q-tab-panel>
|
||||
<q-tab-panel v-if="activeTabs.includes('tasks')" name="tasks" class="q-pa-none">
|
||||
<q-tab-panel
|
||||
v-if="activeTabs.includes('tasks')"
|
||||
name="tasks"
|
||||
class="q-pa-none"
|
||||
>
|
||||
<AutomatedTasksTab />
|
||||
</q-tab-panel>
|
||||
<q-tab-panel v-if="activeTabs.includes('patches')" name="patches" class="q-pa-none">
|
||||
<q-tab-panel
|
||||
v-if="activeTabs.includes('patches')"
|
||||
name="patches"
|
||||
class="q-pa-none"
|
||||
>
|
||||
<WinUpdateTab />
|
||||
</q-tab-panel>
|
||||
<q-tab-panel v-if="activeTabs.includes('software')" name="software" class="q-pa-none">
|
||||
<q-tab-panel
|
||||
v-if="activeTabs.includes('software')"
|
||||
name="software"
|
||||
class="q-pa-none"
|
||||
>
|
||||
<SoftwareTab />
|
||||
</q-tab-panel>
|
||||
<q-tab-panel v-if="activeTabs.includes('history')" name="history" class="q-pa-none">
|
||||
<q-tab-panel
|
||||
v-if="activeTabs.includes('history')"
|
||||
name="history"
|
||||
class="q-pa-none"
|
||||
>
|
||||
<HistoryTab />
|
||||
</q-tab-panel>
|
||||
<q-tab-panel v-if="activeTabs.includes('notes')" name="notes" class="q-pa-none">
|
||||
<q-tab-panel
|
||||
v-if="activeTabs.includes('notes')"
|
||||
name="notes"
|
||||
class="q-pa-none"
|
||||
>
|
||||
<NotesTab />
|
||||
</q-tab-panel>
|
||||
<q-tab-panel v-if="activeTabs.includes('assets')" name="assets" class="q-pa-none">
|
||||
<q-tab-panel
|
||||
v-if="activeTabs.includes('assets')"
|
||||
name="assets"
|
||||
class="q-pa-none"
|
||||
>
|
||||
<AssetsTab />
|
||||
</q-tab-panel>
|
||||
<q-tab-panel v-if="activeTabs.includes('debug')" name="debug" class="q-pa-none">
|
||||
<q-tab-panel
|
||||
v-if="activeTabs.includes('debug')"
|
||||
name="debug"
|
||||
class="q-pa-none"
|
||||
>
|
||||
<DebugTab />
|
||||
</q-tab-panel>
|
||||
<q-tab-panel v-if="activeTabs.includes('audit')" name="audit" class="q-pa-none">
|
||||
<q-tab-panel
|
||||
v-if="activeTabs.includes('audit')"
|
||||
name="audit"
|
||||
class="q-pa-none"
|
||||
>
|
||||
<AuditTab />
|
||||
</q-tab-panel>
|
||||
</q-tab-panels>
|
||||
@@ -156,7 +198,18 @@ export default {
|
||||
props: {
|
||||
activeTabs: {
|
||||
type: Array,
|
||||
default: ["summary", "checks", "tasks", "patches", "software", "history", "notes", "assets", "debug", "audit"],
|
||||
default: () => [
|
||||
"summary",
|
||||
"checks",
|
||||
"tasks",
|
||||
"patches",
|
||||
"software",
|
||||
"history",
|
||||
"notes",
|
||||
"assets",
|
||||
"debug",
|
||||
"audit",
|
||||
],
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
|
@@ -9,7 +9,10 @@
|
||||
</q-bar>
|
||||
<q-table
|
||||
dense
|
||||
:table-class="{ 'table-bgcolor': !$q.dark.isActive, 'table-bgcolor-dark': $q.dark.isActive }"
|
||||
:table-class="{
|
||||
'table-bgcolor': !$q.dark.isActive,
|
||||
'table-bgcolor-dark': $q.dark.isActive,
|
||||
}"
|
||||
class="tabs-tbl-sticky"
|
||||
style="max-height: 70vh"
|
||||
binary-state-sort
|
||||
@@ -22,10 +25,20 @@
|
||||
:rows-per-page-options="[0]"
|
||||
>
|
||||
<template v-slot:top>
|
||||
<q-btn flat dense icon="add" label="New Role" @click="showAddRoleModal" />
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
icon="add"
|
||||
label="New Role"
|
||||
@click="showAddRoleModal"
|
||||
/>
|
||||
</template>
|
||||
<template v-slot:body="props">
|
||||
<q-tr :props="props" @dblclick="showEditRoleModal(props.row)" class="cursor-pointer">
|
||||
<q-tr
|
||||
:props="props"
|
||||
@dblclick="showEditRoleModal(props.row)"
|
||||
class="cursor-pointer"
|
||||
>
|
||||
<q-menu context-menu auto-close>
|
||||
<q-list dense style="min-width: 200px">
|
||||
<q-item clickable @click="showEditRoleModal(props.row)">
|
||||
@@ -34,7 +47,11 @@
|
||||
</q-item-section>
|
||||
<q-item-section>Edit</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable @click="deleteRole(props.row)" :disable="props.row.user_count > 0">
|
||||
<q-item
|
||||
clickable
|
||||
@click="deleteRole(props.row)"
|
||||
:disable="props.row.user_count > 0"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="delete" />
|
||||
</q-item-section>
|
||||
@@ -50,7 +67,12 @@
|
||||
</q-menu>
|
||||
<q-td key="name" :props="props">{{ props.row.name }}</q-td>
|
||||
<q-td key="is_superuser" :props="props">
|
||||
<q-icon v-if="props.row.is_superuser" name="done" color="primary" size="sm" />
|
||||
<q-icon
|
||||
v-if="props.row.is_superuser"
|
||||
name="done"
|
||||
color="primary"
|
||||
size="sm"
|
||||
/>
|
||||
</q-td>
|
||||
<q-td key="user_count" :props="props">
|
||||
{{ props.row.user_count }}
|
||||
@@ -75,14 +97,26 @@ import RolesForm from "@/components/accounts/RolesForm";
|
||||
// static data
|
||||
const columns = [
|
||||
{ name: "name", label: "Name", field: "name", align: "left", sortable: true },
|
||||
{ name: "is_superuser", label: "Superuser", field: "is_superuser", align: "left", sortable: true },
|
||||
{ name: "user_count", label: "Assigned Users", field: "user_count", align: "left", sortable: true },
|
||||
{
|
||||
name: "is_superuser",
|
||||
label: "Superuser",
|
||||
field: "is_superuser",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "user_count",
|
||||
label: "Assigned Users",
|
||||
field: "user_count",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
];
|
||||
|
||||
export default {
|
||||
name: "PermissionsManager",
|
||||
emits: [...useDialogPluginComponent.emits],
|
||||
setup(props) {
|
||||
setup() {
|
||||
// setup quasar
|
||||
const $q = useQuasar();
|
||||
const { dialogRef, onDialogHide } = useDialogPluginComponent();
|
||||
|
@@ -14,7 +14,7 @@
|
||||
dense
|
||||
outlined
|
||||
v-model="localRole.name"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section class="scroll" style="height: 70vh">
|
||||
@@ -31,10 +31,22 @@
|
||||
<q-separator />
|
||||
<q-card-section class="row">
|
||||
<div class="q-gutter-sm">
|
||||
<q-checkbox v-model="localRole.can_list_accounts" label="List User Accounts" />
|
||||
<q-checkbox v-model="localRole.can_manage_accounts" label="Manage User Accounts" />
|
||||
<q-checkbox v-model="localRole.can_list_roles" label="List Roles" />
|
||||
<q-checkbox v-model="localRole.can_manage_roles" label="Manage Roles" />
|
||||
<q-checkbox
|
||||
v-model="localRole.can_list_accounts"
|
||||
label="List User Accounts"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_manage_accounts"
|
||||
label="Manage User Accounts"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_list_roles"
|
||||
label="List Roles"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_manage_roles"
|
||||
label="Manage Roles"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
@@ -42,38 +54,116 @@
|
||||
<q-separator />
|
||||
<q-card-section class="row">
|
||||
<div class="q-gutter-sm">
|
||||
<q-checkbox v-model="localRole.can_list_agents" label="List Agents" />
|
||||
<q-checkbox v-model="localRole.can_list_agent_history" label="List Agent History" />
|
||||
<q-checkbox v-model="localRole.can_use_mesh" label="Use MeshCentral" />
|
||||
<q-checkbox v-model="localRole.can_uninstall_agents" label="Uninstall Agents" />
|
||||
<q-checkbox v-model="localRole.can_ping_agents" label="Ping Agents" />
|
||||
<q-checkbox v-model="localRole.can_update_agents" label="Update Agents" />
|
||||
<q-checkbox v-model="localRole.can_edit_agent" label="Edit Agents" />
|
||||
<q-checkbox v-model="localRole.can_manage_procs" label="Manage Processes" />
|
||||
<q-checkbox v-model="localRole.can_view_eventlogs" label="View Event Logs" />
|
||||
<q-checkbox v-model="localRole.can_send_cmd" label="Send Command" />
|
||||
<q-checkbox v-model="localRole.can_reboot_agents" label="Reboot Agents" />
|
||||
<q-checkbox v-model="localRole.can_install_agents" label="Install Agents" />
|
||||
<q-checkbox v-model="localRole.can_run_scripts" label="Run Script" />
|
||||
<q-checkbox v-model="localRole.can_run_bulk" label="Bulk Actions" />
|
||||
<q-checkbox v-model="localRole.can_recover_agents" label="Recover Agents" />
|
||||
<q-checkbox
|
||||
v-model="localRole.can_list_agents"
|
||||
label="List Agents"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_list_agent_history"
|
||||
label="List Agent History"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_use_mesh"
|
||||
label="Use MeshCentral"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_uninstall_agents"
|
||||
label="Uninstall Agents"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_ping_agents"
|
||||
label="Ping Agents"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_update_agents"
|
||||
label="Update Agents"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_edit_agent"
|
||||
label="Edit Agents"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_manage_procs"
|
||||
label="Manage Processes"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_view_eventlogs"
|
||||
label="View Event Logs"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_send_cmd"
|
||||
label="Send Command"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_reboot_agents"
|
||||
label="Reboot Agents"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_install_agents"
|
||||
label="Install Agents"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_run_scripts"
|
||||
label="Run Script"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_run_bulk"
|
||||
label="Bulk Actions"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_recover_agents"
|
||||
label="Recover Agents"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
<div class="text-subtitle2">Core</div>
|
||||
<q-separator />
|
||||
<q-card-section class="row">
|
||||
<div class="q-gutter-sm">
|
||||
<q-checkbox v-model="localRole.can_list_notes" label="List Notes" />
|
||||
<q-checkbox v-model="localRole.can_manage_notes" label="Manage Notes" />
|
||||
<q-checkbox v-model="localRole.can_view_core_settings" label="View Global Settings" />
|
||||
<q-checkbox v-model="localRole.can_edit_core_settings" label="Edit Global Settings" />
|
||||
<q-checkbox v-model="localRole.can_do_server_maint" label="Do Server Maintenance" />
|
||||
<q-checkbox v-model="localRole.can_code_sign" label="Manage Code Signing" />
|
||||
<q-checkbox v-model="localRole.can_list_api_keys" label="List API Keys" />
|
||||
<q-checkbox v-model="localRole.can_manage_api_keys" label="Manage API Keys" />
|
||||
<q-checkbox v-model="localRole.can_run_urlactions" label="Run URL Actions" />
|
||||
<q-checkbox v-model="localRole.can_view_customfields" label="View Custom Fields" />
|
||||
<q-checkbox v-model="localRole.can_manage_customfields" label="Edit Custom Fields" />
|
||||
<q-checkbox
|
||||
v-model="localRole.can_list_notes"
|
||||
label="List Notes"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_manage_notes"
|
||||
label="Manage Notes"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_view_core_settings"
|
||||
label="View Global Settings"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_edit_core_settings"
|
||||
label="Edit Global Settings"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_do_server_maint"
|
||||
label="Do Server Maintenance"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_code_sign"
|
||||
label="Manage Code Signing"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_list_api_keys"
|
||||
label="List API Keys"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_manage_api_keys"
|
||||
label="Manage API Keys"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_run_urlactions"
|
||||
label="Run URL Actions"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_view_customfields"
|
||||
label="View Custom Fields"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_manage_customfields"
|
||||
label="Edit Custom Fields"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
@@ -81,9 +171,18 @@
|
||||
<q-separator />
|
||||
<q-card-section class="row">
|
||||
<div class="q-gutter-sm">
|
||||
<q-checkbox v-model="localRole.can_list_checks" label="List Checks" />
|
||||
<q-checkbox v-model="localRole.can_manage_checks" label="Manage Checks" />
|
||||
<q-checkbox v-model="localRole.can_run_checks" label="Run Checks" />
|
||||
<q-checkbox
|
||||
v-model="localRole.can_list_checks"
|
||||
label="List Checks"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_manage_checks"
|
||||
label="Manage Checks"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_run_checks"
|
||||
label="Run Checks"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
@@ -91,12 +190,30 @@
|
||||
<q-separator />
|
||||
<q-card-section class="row">
|
||||
<div class="q-gutter-sm">
|
||||
<q-checkbox v-model="localRole.can_list_clients" label="List Clients" />
|
||||
<q-checkbox v-model="localRole.can_manage_clients" label="Manage Clients" />
|
||||
<q-checkbox v-model="localRole.can_list_sites" label="List Sites" />
|
||||
<q-checkbox v-model="localRole.can_manage_sites" label="Manage Sites" />
|
||||
<q-checkbox v-model="localRole.can_list_deployments" label="List Deployments" />
|
||||
<q-checkbox v-model="localRole.can_manage_deployments" label="Manage Deployments" />
|
||||
<q-checkbox
|
||||
v-model="localRole.can_list_clients"
|
||||
label="List Clients"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_manage_clients"
|
||||
label="Manage Clients"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_list_sites"
|
||||
label="List Sites"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_manage_sites"
|
||||
label="Manage Sites"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_list_deployments"
|
||||
label="List Deployments"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_manage_deployments"
|
||||
label="Manage Deployments"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
@@ -131,8 +248,14 @@
|
||||
<q-separator />
|
||||
<q-card-section class="row">
|
||||
<div class="q-gutter-sm">
|
||||
<q-checkbox v-model="localRole.can_list_automation_policies" label="List Automation Policies" />
|
||||
<q-checkbox v-model="localRole.can_manage_automation_policies" label="Manage Automation Policies" />
|
||||
<q-checkbox
|
||||
v-model="localRole.can_list_automation_policies"
|
||||
label="List Automation Policies"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_manage_automation_policies"
|
||||
label="Manage Automation Policies"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
@@ -140,9 +263,18 @@
|
||||
<q-separator />
|
||||
<q-card-section class="row">
|
||||
<div class="q-gutter-sm">
|
||||
<q-checkbox v-model="localRole.can_list_autotasks" label="List Tasks" />
|
||||
<q-checkbox v-model="localRole.can_manage_autotasks" label="Manage Tasks" />
|
||||
<q-checkbox v-model="localRole.can_run_autotasks" label="Run Tasks" />
|
||||
<q-checkbox
|
||||
v-model="localRole.can_list_autotasks"
|
||||
label="List Tasks"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_manage_autotasks"
|
||||
label="Manage Tasks"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_run_autotasks"
|
||||
label="Run Tasks"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
@@ -150,10 +282,22 @@
|
||||
<q-separator />
|
||||
<q-card-section class="row">
|
||||
<div class="q-gutter-sm">
|
||||
<q-checkbox v-model="localRole.can_view_auditlogs" label="View Audit Logs" />
|
||||
<q-checkbox v-model="localRole.can_view_debuglogs" label="View Debug Logs" />
|
||||
<q-checkbox v-model="localRole.can_list_pendingactions" label="List Pending Actions" />
|
||||
<q-checkbox v-model="localRole.can_manage_pendingactions" label="Manage Pending Actions" />
|
||||
<q-checkbox
|
||||
v-model="localRole.can_view_auditlogs"
|
||||
label="View Audit Logs"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_view_debuglogs"
|
||||
label="View Debug Logs"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_list_pendingactions"
|
||||
label="List Pending Actions"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_manage_pendingactions"
|
||||
label="Manage Pending Actions"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
@@ -161,8 +305,14 @@
|
||||
<q-separator />
|
||||
<q-card-section class="row">
|
||||
<div class="q-gutter-sm">
|
||||
<q-checkbox v-model="localRole.can_list_scripts" label="List Scripts" />
|
||||
<q-checkbox v-model="localRole.can_manage_scripts" label="Manage Scripts" />
|
||||
<q-checkbox
|
||||
v-model="localRole.can_list_scripts"
|
||||
label="List Scripts"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_manage_scripts"
|
||||
label="Manage Scripts"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
@@ -170,10 +320,22 @@
|
||||
<q-separator />
|
||||
<q-card-section class="row">
|
||||
<div class="q-gutter-sm">
|
||||
<q-checkbox v-model="localRole.can_list_alerts" label="List Alerts" />
|
||||
<q-checkbox v-model="localRole.can_manage_alerts" label="Manage Alerts" />
|
||||
<q-checkbox v-model="localRole.can_list_alerttemplates" label="List Alert Templates" />
|
||||
<q-checkbox v-model="localRole.can_manage_alerttemplates" label="Manage Alert Templates" />
|
||||
<q-checkbox
|
||||
v-model="localRole.can_list_alerts"
|
||||
label="List Alerts"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_manage_alerts"
|
||||
label="Manage Alerts"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_list_alerttemplates"
|
||||
label="List Alert Templates"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_manage_alerttemplates"
|
||||
label="Manage Alert Templates"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
@@ -181,7 +343,10 @@
|
||||
<q-separator />
|
||||
<q-card-section class="row">
|
||||
<div class="q-gutter-sm">
|
||||
<q-checkbox v-model="localRole.can_manage_winsvcs" label="Manage Windows Services" />
|
||||
<q-checkbox
|
||||
v-model="localRole.can_manage_winsvcs"
|
||||
label="Manage Windows Services"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
@@ -189,8 +354,14 @@
|
||||
<q-separator />
|
||||
<q-card-section class="row">
|
||||
<div class="q-gutter-sm">
|
||||
<q-checkbox v-model="localRole.can_list_software" label="List Software" />
|
||||
<q-checkbox v-model="localRole.can_manage_software" label="Manage Software" />
|
||||
<q-checkbox
|
||||
v-model="localRole.can_list_software"
|
||||
label="List Software"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localRole.can_manage_software"
|
||||
label="Manage Software"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
@@ -198,13 +369,23 @@
|
||||
<q-separator />
|
||||
<q-card-section class="row">
|
||||
<div class="q-gutter-sm">
|
||||
<q-checkbox v-model="localRole.can_manage_winupdates" label="Manage Windows Updates" />
|
||||
<q-checkbox
|
||||
v-model="localRole.can_manage_winupdates"
|
||||
label="Manage Windows Updates"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
</q-card-section>
|
||||
<q-card-actions align="right">
|
||||
<q-btn dense flat label="Cancel" v-close-popup />
|
||||
<q-btn :loading="loading" dense flat label="Save" color="primary" type="submit" />
|
||||
<q-btn
|
||||
:loading="loading"
|
||||
dense
|
||||
flat
|
||||
label="Save"
|
||||
color="primary"
|
||||
type="submit"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-form>
|
||||
</q-card>
|
||||
@@ -323,7 +504,9 @@ export default {
|
||||
async function onSubmit() {
|
||||
loading.value = true;
|
||||
try {
|
||||
const result = props.role ? await editRole(role.value.id, role.value) : await saveRole(role.value);
|
||||
const result = props.role
|
||||
? await editRole(role.value.id, role.value)
|
||||
: await saveRole(role.value);
|
||||
notifySuccess(result);
|
||||
onDialogOK();
|
||||
} catch (e) {
|
||||
@@ -334,7 +517,8 @@ export default {
|
||||
|
||||
watch(
|
||||
() => role.value.is_superuser,
|
||||
(newValue, oldValue) => {
|
||||
(newValue) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
Object.keys(role.value).forEach((key, index) => {
|
||||
if (typeof role.value[key] === "boolean") {
|
||||
role.value[key] = newValue;
|
||||
|
@@ -15,7 +15,12 @@
|
||||
<q-item-section>Pending Agent Actions</q-item-section>
|
||||
</q-item>
|
||||
<!-- take control -->
|
||||
<q-item clickable v-ripple v-close-popup @click="runTakeControl(agent.agent_id)">
|
||||
<q-item
|
||||
clickable
|
||||
v-ripple
|
||||
v-close-popup
|
||||
@click="runTakeControl(agent.agent_id)"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon size="xs" name="fas fa-desktop" />
|
||||
</q-item-section>
|
||||
@@ -39,7 +44,9 @@
|
||||
dense
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="runURLAction({ agent_id: agent.agent_id, action: action.id })"
|
||||
@click="
|
||||
runURLAction({ agent_id: agent.agent_id, action: action.id })
|
||||
"
|
||||
>
|
||||
{{ action.name }}
|
||||
</q-item>
|
||||
@@ -85,7 +92,11 @@
|
||||
</q-menu>
|
||||
</q-item>
|
||||
|
||||
<q-item clickable v-close-popup @click="runRemoteBackground(agent.agent_id, agent.plat)">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="runRemoteBackground(agent.agent_id, agent.plat)"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon size="xs" name="fas fa-cogs" />
|
||||
</q-item-section>
|
||||
@@ -98,7 +109,11 @@
|
||||
<q-icon size="xs" name="construction" />
|
||||
</q-item-section>
|
||||
<q-item-section>
|
||||
{{ agent.maintenance_mode ? "Disable Maintenance Mode" : "Enable Maintenance Mode" }}
|
||||
{{
|
||||
agent.maintenance_mode
|
||||
? "Disable Maintenance Mode"
|
||||
: "Enable Maintenance Mode"
|
||||
}}
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
|
||||
@@ -215,7 +230,7 @@ export default {
|
||||
props: {
|
||||
agent: !Object,
|
||||
},
|
||||
setup(props) {
|
||||
setup() {
|
||||
// setup quasar
|
||||
const $q = useQuasar();
|
||||
|
||||
@@ -252,7 +267,9 @@ export default {
|
||||
urlActions.value = await fetchURLActions();
|
||||
|
||||
if (urlActions.value.length === 0) {
|
||||
notifyWarning("No URL Actions configured. Go to Settings > Global Settings > URL Actions");
|
||||
notifyWarning(
|
||||
"No URL Actions configured. Go to Settings > Global Settings > URL Actions"
|
||||
);
|
||||
return;
|
||||
}
|
||||
} catch (e) {}
|
||||
@@ -283,9 +300,11 @@ export default {
|
||||
|
||||
menuLoading.value = true;
|
||||
try {
|
||||
const data = await fetchScripts({ showCommunityScripts: store.state.showCommunityScripts });
|
||||
const data = await fetchScripts({
|
||||
showCommunityScripts: store.state.showCommunityScripts,
|
||||
});
|
||||
|
||||
const scripts = data.filter(script => !!script.favorite);
|
||||
const scripts = data.filter((script) => !!script.favorite);
|
||||
|
||||
if (scripts.length === 0) {
|
||||
notifyWarning("You don't have any scripts favorited!");
|
||||
@@ -293,7 +312,7 @@ export default {
|
||||
}
|
||||
|
||||
favoriteScripts.value = scripts
|
||||
.map(script => ({
|
||||
.map((script) => ({
|
||||
label: script.name,
|
||||
value: script.id,
|
||||
timeout: script.default_timeout,
|
||||
@@ -311,8 +330,12 @@ export default {
|
||||
};
|
||||
|
||||
try {
|
||||
const result = await editAgent(agent.agent_id, data);
|
||||
notifySuccess(`Maintenance mode was ${agent.maintenance_mode ? "disabled" : "enabled"} on ${agent.hostname}`);
|
||||
await editAgent(agent.agent_id, data);
|
||||
notifySuccess(
|
||||
`Maintenance mode was ${
|
||||
agent.maintenance_mode ? "disabled" : "enabled"
|
||||
} on ${agent.hostname}`
|
||||
);
|
||||
store.commit("setRefreshSummaryTab", true);
|
||||
refreshDashboard();
|
||||
} catch (e) {
|
||||
@@ -322,7 +345,7 @@ export default {
|
||||
|
||||
async function runPatchStatusScan(agent) {
|
||||
try {
|
||||
const result = await runAgentUpdateScan(agent.agent_id);
|
||||
await runAgentUpdateScan(agent.agent_id);
|
||||
notifySuccess(`Scan will be run shortly on ${agent.hostname}`);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
@@ -365,7 +388,7 @@ export default {
|
||||
}).onOk(async () => {
|
||||
$q.loading.show();
|
||||
try {
|
||||
const result = await agentRebootNow(agent.agent_id);
|
||||
await agentRebootNow(agent.agent_id);
|
||||
notifySuccess(`${agent.hostname} will now be restarted`);
|
||||
$q.loading.hide();
|
||||
} catch (e) {
|
||||
@@ -426,21 +449,25 @@ export default {
|
||||
|
||||
function deleteAgent(agent) {
|
||||
$q.dialog({
|
||||
title: `Please type <code style="color:red">yes</code> in the box below to confirm deletion.`,
|
||||
title:
|
||||
'Please type <code style="color:red">yes</code> in the box below to confirm deletion.',
|
||||
prompt: {
|
||||
model: "",
|
||||
type: "text",
|
||||
isValid: val => val === "yes",
|
||||
isValid: (val) => val === "yes",
|
||||
},
|
||||
cancel: true,
|
||||
ok: { label: "Uninstall", color: "negative" },
|
||||
persistent: true,
|
||||
html: true,
|
||||
}).onOk(async val => {
|
||||
}).onOk(async () => {
|
||||
try {
|
||||
const data = await removeAgent(agent.agent_id);
|
||||
notifySuccess(data);
|
||||
refreshDashboard(false /* clearTreeSelected */, true /* clearSubTable */);
|
||||
refreshDashboard(
|
||||
false /* clearTreeSelected */,
|
||||
true /* clearSubTable */
|
||||
);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
@@ -87,7 +87,7 @@ import WmiDetail from "@/components/agents/WmiDetail";
|
||||
export default {
|
||||
name: "AssetsTab",
|
||||
components: { WmiDetail },
|
||||
setup(props) {
|
||||
setup() {
|
||||
// setup vuex
|
||||
const store = useStore();
|
||||
const selectedAgent = computed(() => store.state.selectedRow);
|
||||
@@ -105,7 +105,7 @@ export default {
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
watch(selectedAgent, (newValue, oldValue) => {
|
||||
watch(selectedAgent, (newValue) => {
|
||||
if (newValue) {
|
||||
getWMIData();
|
||||
}
|
||||
@@ -125,4 +125,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@@ -6,7 +6,10 @@
|
||||
<div v-else>
|
||||
<q-table
|
||||
dense
|
||||
:table-class="{ 'table-bgcolor': !$q.dark.isActive, 'table-bgcolor-dark': $q.dark.isActive }"
|
||||
:table-class="{
|
||||
'table-bgcolor': !$q.dark.isActive,
|
||||
'table-bgcolor-dark': $q.dark.isActive,
|
||||
}"
|
||||
class="tabs-tbl-sticky"
|
||||
:style="{ 'max-height': tabHeight }"
|
||||
:rows="tasks"
|
||||
@@ -20,8 +23,23 @@
|
||||
no-data-label="No tasks"
|
||||
>
|
||||
<template v-slot:top>
|
||||
<q-btn class="q-mr-sm" dense flat push @click="getTasks" icon="refresh" />
|
||||
<q-btn icon="add" label="Add Task" no-caps dense flat push @click="showAddTask" />
|
||||
<q-btn
|
||||
class="q-mr-sm"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
@click="getTasks"
|
||||
icon="refresh"
|
||||
/>
|
||||
<q-btn
|
||||
icon="add"
|
||||
label="Add Task"
|
||||
no-caps
|
||||
dense
|
||||
flat
|
||||
push
|
||||
@click="showAddTask"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template v-slot:loading>
|
||||
@@ -79,7 +97,11 @@
|
||||
|
||||
<!-- body slots -->
|
||||
<template v-slot:body="props">
|
||||
<q-tr :props="props" class="cursor-pointer" @dblclick="showEditTask(props.row)">
|
||||
<q-tr
|
||||
:props="props"
|
||||
class="cursor-pointer"
|
||||
@dblclick="showEditTask(props.row)"
|
||||
>
|
||||
<!-- context menu -->
|
||||
<q-menu context-menu>
|
||||
<q-list dense style="min-width: 200px">
|
||||
@@ -89,13 +111,23 @@
|
||||
</q-item-section>
|
||||
<q-item-section>Run task now</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable v-close-popup @click="showEditTask(props.row)" v-if="!props.row.policy">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showEditTask(props.row)"
|
||||
v-if="!props.row.policy"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="edit" />
|
||||
</q-item-section>
|
||||
<q-item-section>Edit</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable v-close-popup @click="deleteTask(props.row)" v-if="!props.row.policy">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="deleteTask(props.row)"
|
||||
v-if="!props.row.policy"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="delete" />
|
||||
</q-item-section>
|
||||
@@ -111,7 +143,9 @@
|
||||
<q-td>
|
||||
<q-checkbox
|
||||
dense
|
||||
@update:model-value="editTask(props.row, { enabled: !props.row.enabled })"
|
||||
@update:model-value="
|
||||
editTask(props.row, { enabled: !props.row.enabled })
|
||||
"
|
||||
v-model="props.row.enabled"
|
||||
:disable="!!props.row.policy"
|
||||
/>
|
||||
@@ -119,18 +153,26 @@
|
||||
<!-- text alert -->
|
||||
<q-td>
|
||||
<q-checkbox
|
||||
v-if="props.row.alert_template && props.row.alert_template.always_text !== null"
|
||||
v-if="
|
||||
props.row.alert_template &&
|
||||
props.row.alert_template.always_text !== null
|
||||
"
|
||||
v-model="props.row.alert_template.always_text"
|
||||
disable
|
||||
dense
|
||||
>
|
||||
<q-tooltip> Setting is overridden by alert template: {{ props.row.alert_template.name }} </q-tooltip>
|
||||
<q-tooltip>
|
||||
Setting is overridden by alert template:
|
||||
{{ props.row.alert_template.name }}
|
||||
</q-tooltip>
|
||||
</q-checkbox>
|
||||
|
||||
<q-checkbox
|
||||
v-else
|
||||
dense
|
||||
@update:model-value="editTask(props.row, { text_alert: !props.row.text_alert })"
|
||||
@update:model-value="
|
||||
editTask(props.row, { text_alert: !props.row.text_alert })
|
||||
"
|
||||
v-model="props.row.text_alert"
|
||||
:disable="!!props.row.policy"
|
||||
/>
|
||||
@@ -138,18 +180,26 @@
|
||||
<!-- email alert -->
|
||||
<q-td>
|
||||
<q-checkbox
|
||||
v-if="props.row.alert_template && props.row.alert_template.always_email !== null"
|
||||
v-if="
|
||||
props.row.alert_template &&
|
||||
props.row.alert_template.always_email !== null
|
||||
"
|
||||
v-model="props.row.alert_template.always_email"
|
||||
disable
|
||||
dense
|
||||
>
|
||||
<q-tooltip> Setting is overridden by alert template: {{ props.row.alert_template.name }} </q-tooltip>
|
||||
<q-tooltip>
|
||||
Setting is overridden by alert template:
|
||||
{{ props.row.alert_template.name }}
|
||||
</q-tooltip>
|
||||
</q-checkbox>
|
||||
|
||||
<q-checkbox
|
||||
v-else
|
||||
dense
|
||||
@update:model-value="editTask(props.row, { email_alert: !props.row.email_alert })"
|
||||
@update:model-value="
|
||||
editTask(props.row, { email_alert: !props.row.email_alert })
|
||||
"
|
||||
v-model="props.row.email_alert"
|
||||
:disable="!!props.row.policy"
|
||||
/>
|
||||
@@ -157,44 +207,73 @@
|
||||
<!-- dashboard alert -->
|
||||
<q-td>
|
||||
<q-checkbox
|
||||
v-if="props.row.alert_template && props.row.alert_template.always_alert !== null"
|
||||
v-if="
|
||||
props.row.alert_template &&
|
||||
props.row.alert_template.always_alert !== null
|
||||
"
|
||||
v-model="props.row.alert_template.always_alert"
|
||||
disable
|
||||
dense
|
||||
>
|
||||
<q-tooltip> Setting is overridden by alert template: {{ props.row.alert_template.name }} </q-tooltip>
|
||||
<q-tooltip>
|
||||
Setting is overridden by alert template:
|
||||
{{ props.row.alert_template.name }}
|
||||
</q-tooltip>
|
||||
</q-checkbox>
|
||||
|
||||
<q-checkbox
|
||||
v-else
|
||||
dense
|
||||
@update:model-value="editTask(props.row, { dashboard_alert: !props.row.dashboard_alert })"
|
||||
@update:model-value="
|
||||
editTask(props.row, {
|
||||
dashboard_alert: !props.row.dashboard_alert,
|
||||
})
|
||||
"
|
||||
v-model="props.row.dashboard_alert"
|
||||
:disable="!!props.row.policy"
|
||||
/>
|
||||
</q-td>
|
||||
<!-- policy check icon -->
|
||||
<q-td>
|
||||
<q-icon v-if="props.row.policy" style="font-size: 1.3rem" name="policy">
|
||||
<q-icon
|
||||
v-if="props.row.policy"
|
||||
style="font-size: 1.3rem"
|
||||
name="policy"
|
||||
>
|
||||
<q-tooltip>This task is managed by a policy</q-tooltip>
|
||||
</q-icon>
|
||||
</q-td>
|
||||
|
||||
<!-- is collector task -->
|
||||
<q-td>
|
||||
<q-icon v-if="!!props.row.custom_field" style="font-size: 1.3rem" name="check">
|
||||
<q-tooltip>The task updates a custom field on the agent</q-tooltip>
|
||||
<q-icon
|
||||
v-if="!!props.row.custom_field"
|
||||
style="font-size: 1.3rem"
|
||||
name="check"
|
||||
>
|
||||
<q-tooltip
|
||||
>The task updates a custom field on the agent</q-tooltip
|
||||
>
|
||||
</q-icon>
|
||||
</q-td>
|
||||
<!-- status icon -->
|
||||
<q-td v-if="Object.keys(props.row.task_result).length === 0"></q-td>
|
||||
<q-td v-else-if="props.row.task_result.status === 'passing'">
|
||||
<q-icon style="font-size: 1.3rem" color="positive" name="check_circle">
|
||||
<q-icon
|
||||
style="font-size: 1.3rem"
|
||||
color="positive"
|
||||
name="check_circle"
|
||||
>
|
||||
<q-tooltip>Passing</q-tooltip>
|
||||
</q-icon>
|
||||
</q-td>
|
||||
<q-td v-else-if="props.row.task_result.status === 'failing'">
|
||||
<q-icon v-if="props.row.alert_severity === 'info'" style="font-size: 1.3rem" color="info" name="info">
|
||||
<q-icon
|
||||
v-if="props.row.alert_severity === 'info'"
|
||||
style="font-size: 1.3rem"
|
||||
color="info"
|
||||
name="info"
|
||||
>
|
||||
<q-tooltip>Informational</q-tooltip>
|
||||
</q-icon>
|
||||
<q-icon
|
||||
@@ -205,7 +284,12 @@
|
||||
>
|
||||
<q-tooltip>Warning</q-tooltip>
|
||||
</q-icon>
|
||||
<q-icon v-else style="font-size: 1.3rem" color="negative" name="error">
|
||||
<q-icon
|
||||
v-else
|
||||
style="font-size: 1.3rem"
|
||||
color="negative"
|
||||
name="error"
|
||||
>
|
||||
<q-tooltip>Error</q-tooltip>
|
||||
</q-icon>
|
||||
</q-td>
|
||||
@@ -213,13 +297,22 @@
|
||||
<!-- name -->
|
||||
<q-td>{{ props.row.name }}</q-td>
|
||||
<!-- sync status -->
|
||||
<q-td v-if="props.row.task_result.sync_status === 'notsynced'">Will sync on next agent checkin</q-td>
|
||||
<q-td v-else-if="props.row.task_result.sync_status === 'synced'">Synced with agent</q-td>
|
||||
<q-td v-else-if="props.row.task_result.sync_status === 'pendingdeletion'">Pending deletion on agent</q-td>
|
||||
<q-td v-if="props.row.task_result.sync_status === 'notsynced'"
|
||||
>Will sync on next agent checkin</q-td
|
||||
>
|
||||
<q-td v-else-if="props.row.task_result.sync_status === 'synced'"
|
||||
>Synced with agent</q-td
|
||||
>
|
||||
<q-td
|
||||
v-else-if="props.row.task_result.sync_status === 'pendingdeletion'"
|
||||
>Pending deletion on agent</q-td
|
||||
>
|
||||
<q-td v-else>Waiting for task creation on agent</q-td>
|
||||
<q-td
|
||||
v-if="
|
||||
props.row.task_result.retcode !== null || props.row.task_result.stdout || props.row.task_result.stderr
|
||||
props.row.task_result.retcode !== null ||
|
||||
props.row.task_result.stdout ||
|
||||
props.row.task_result.stderr
|
||||
"
|
||||
>
|
||||
<span
|
||||
@@ -230,13 +323,17 @@
|
||||
>
|
||||
</q-td>
|
||||
<q-td v-else>Awaiting output</q-td>
|
||||
<q-td v-if="props.row.task_result.last_run">{{ formatDate(props.row.task_result.last_run) }}</q-td>
|
||||
<q-td v-if="props.row.task_result.last_run">{{
|
||||
formatDate(props.row.task_result.last_run)
|
||||
}}</q-td>
|
||||
<q-td v-else>Has not run yet</q-td>
|
||||
<q-td>{{ props.row.schedule }}</q-td>
|
||||
<q-td>
|
||||
<span v-if="props.row.check_name">
|
||||
{{ truncateText(props.row.check_name, 40) }}
|
||||
<q-tooltip v-if="props.row.check_name.length > 40">{{ props.row.check_name }}</q-tooltip>
|
||||
<q-tooltip v-if="props.row.check_name.length > 40">{{
|
||||
props.row.check_name
|
||||
}}</q-tooltip>
|
||||
</span>
|
||||
</q-td>
|
||||
</q-tr>
|
||||
@@ -266,10 +363,22 @@ const columns = [
|
||||
{ name: "emailalert", field: "email_alert", align: "left" },
|
||||
{ name: "dashboardalert", field: "dashboard_alert", align: "left" },
|
||||
{ name: "policystatus", align: "left" },
|
||||
{ name: "collector", label: "Collector", field: "custom_field", align: "left", sortable: true },
|
||||
{
|
||||
name: "collector",
|
||||
label: "Collector",
|
||||
field: "custom_field",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{ name: "status", align: "left" },
|
||||
{ name: "name", label: "Name", field: "name", align: "left", sortable: true },
|
||||
{ name: "sync_status", label: "Sync Status", field: "sync_status", align: "left", sortable: true },
|
||||
{
|
||||
name: "sync_status",
|
||||
label: "Sync Status",
|
||||
field: "sync_status",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "moreinfo",
|
||||
label: "More Info",
|
||||
@@ -302,7 +411,7 @@ const columns = [
|
||||
|
||||
export default {
|
||||
name: "AutomatedTasksTab",
|
||||
setup(props) {
|
||||
setup() {
|
||||
// setup vuex
|
||||
const store = useStore();
|
||||
const selectedAgent = computed(() => store.state.selectedRow);
|
||||
@@ -327,7 +436,9 @@ export default {
|
||||
loading.value = true;
|
||||
try {
|
||||
const result = await fetchAgentTasks(selectedAgent.value);
|
||||
tasks.value = result.filter(task => task.sync_status !== "pendingdeletion");
|
||||
tasks.value = result.filter(
|
||||
(task) => task.sync_status !== "pendingdeletion"
|
||||
);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
@@ -378,7 +489,10 @@ export default {
|
||||
|
||||
loading.value = true;
|
||||
try {
|
||||
const result = await runTask(task.id, task.policy ? { agent_id: selectedAgent.value } : {});
|
||||
const result = await runTask(
|
||||
task.id,
|
||||
task.policy ? { agent_id: selectedAgent.value } : {}
|
||||
);
|
||||
notifySuccess(result);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
@@ -420,7 +534,7 @@ export default {
|
||||
});
|
||||
}
|
||||
|
||||
watch(selectedAgent, (newValue, oldValue) => {
|
||||
watch(selectedAgent, (newValue) => {
|
||||
if (newValue) {
|
||||
getTasks();
|
||||
}
|
||||
@@ -458,4 +572,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@@ -3,7 +3,10 @@
|
||||
<div v-else>
|
||||
<q-table
|
||||
dense
|
||||
:table-class="{ 'table-bgcolor': !$q.dark.isActive, 'table-bgcolor-dark': $q.dark.isActive }"
|
||||
:table-class="{
|
||||
'table-bgcolor': !$q.dark.isActive,
|
||||
'table-bgcolor-dark': $q.dark.isActive,
|
||||
}"
|
||||
class="tabs-tbl-sticky"
|
||||
:style="{ 'max-height': tabHeight }"
|
||||
:rows="checks"
|
||||
@@ -22,10 +25,29 @@
|
||||
|
||||
<!-- table top slot -->
|
||||
<template v-slot:top>
|
||||
<q-btn class="q-mr-sm" dense flat push @click="getChecks" icon="refresh" />
|
||||
<q-btn-dropdown icon="add" label="New" no-caps dense flat class="q-mr-md">
|
||||
<q-btn
|
||||
class="q-mr-sm"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
@click="getChecks"
|
||||
icon="refresh"
|
||||
/>
|
||||
<q-btn-dropdown
|
||||
icon="add"
|
||||
label="New"
|
||||
no-caps
|
||||
dense
|
||||
flat
|
||||
class="q-mr-md"
|
||||
>
|
||||
<q-list dense style="min-width: 200px">
|
||||
<q-item v-if="agentPlatform === 'windows'" clickable v-close-popup @click="showCheckModal('diskspace')">
|
||||
<q-item
|
||||
v-if="agentPlatform === 'windows'"
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showCheckModal('diskspace')"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon size="xs" name="far fa-hdd" />
|
||||
</q-item-section>
|
||||
@@ -37,19 +59,34 @@
|
||||
</q-item-section>
|
||||
<q-item-section>Ping Check</q-item-section>
|
||||
</q-item>
|
||||
<q-item v-if="agentPlatform === 'windows'" clickable v-close-popup @click="showCheckModal('cpuload')">
|
||||
<q-item
|
||||
v-if="agentPlatform === 'windows'"
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showCheckModal('cpuload')"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon size="xs" name="fas fa-microchip" />
|
||||
</q-item-section>
|
||||
<q-item-section>CPU Load Check</q-item-section>
|
||||
</q-item>
|
||||
<q-item v-if="agentPlatform === 'windows'" clickable v-close-popup @click="showCheckModal('memory')">
|
||||
<q-item
|
||||
v-if="agentPlatform === 'windows'"
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showCheckModal('memory')"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon size="xs" name="fas fa-memory" />
|
||||
</q-item-section>
|
||||
<q-item-section>Memory Check</q-item-section>
|
||||
</q-item>
|
||||
<q-item v-if="agentPlatform === 'windows'" clickable v-close-popup @click="showCheckModal('winsvc')">
|
||||
<q-item
|
||||
v-if="agentPlatform === 'windows'"
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showCheckModal('winsvc')"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon size="xs" name="fas fa-cogs" />
|
||||
</q-item-section>
|
||||
@@ -61,7 +98,12 @@
|
||||
</q-item-section>
|
||||
<q-item-section>Script Check</q-item-section>
|
||||
</q-item>
|
||||
<q-item v-if="agentPlatform === 'windows'" clickable v-close-popup @click="showCheckModal('eventlog')">
|
||||
<q-item
|
||||
v-if="agentPlatform === 'windows'"
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showCheckModal('eventlog')"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon size="xs" name="fas fa-clipboard-list" />
|
||||
</q-item-section>
|
||||
@@ -69,7 +111,15 @@
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-btn-dropdown>
|
||||
<q-btn label="Run Checks Now" dense flat push no-caps icon="play_arrow" @click="runChecks" />
|
||||
<q-btn
|
||||
label="Run Checks Now"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
no-caps
|
||||
icon="play_arrow"
|
||||
@click="runChecks"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<!-- header slots -->
|
||||
@@ -103,7 +153,11 @@
|
||||
|
||||
<!-- body slots -->
|
||||
<template v-slot:body="props">
|
||||
<q-tr :props="props" class="cursor-pointer" @dblclick="showCheckModal(props.row.check_type, props.row)">
|
||||
<q-tr
|
||||
:props="props"
|
||||
class="cursor-pointer"
|
||||
@dblclick="showCheckModal(props.row.check_type, props.row)"
|
||||
>
|
||||
<!-- context menu -->
|
||||
<q-menu context-menu>
|
||||
<q-list dense style="min-width: 200px">
|
||||
@@ -118,14 +172,23 @@
|
||||
</q-item-section>
|
||||
<q-item-section>Edit</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable v-close-popup @click="deleteCheck(props.row)" :disable="!!props.row.policy">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="deleteCheck(props.row)"
|
||||
:disable="!!props.row.policy"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="delete" />
|
||||
</q-item-section>
|
||||
<q-item-section>Delete</q-item-section>
|
||||
</q-item>
|
||||
<q-separator></q-separator>
|
||||
<q-item clickable v-close-popup @click="resetCheckStatus(props.row)">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="resetCheckStatus(props.row)"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="info" />
|
||||
</q-item-section>
|
||||
@@ -141,18 +204,26 @@
|
||||
<!-- text alert -->
|
||||
<q-td>
|
||||
<q-checkbox
|
||||
v-if="props.row.alert_template && props.row.alert_template.always_text != null"
|
||||
v-if="
|
||||
props.row.alert_template &&
|
||||
props.row.alert_template.always_text != null
|
||||
"
|
||||
v-model="props.row.alert_template.always_text"
|
||||
disable
|
||||
dense
|
||||
>
|
||||
<q-tooltip> Setting is overridden by alert template: {{ props.row.alert_template.name }} </q-tooltip>
|
||||
<q-tooltip>
|
||||
Setting is overridden by alert template:
|
||||
{{ props.row.alert_template.name }}
|
||||
</q-tooltip>
|
||||
</q-checkbox>
|
||||
|
||||
<q-checkbox
|
||||
v-else
|
||||
dense
|
||||
@update:model-value="editCheck(props.row, { text_alert: !props.row.text_alert })"
|
||||
@update:model-value="
|
||||
editCheck(props.row, { text_alert: !props.row.text_alert })
|
||||
"
|
||||
v-model="props.row.text_alert"
|
||||
:disable="!!props.row.policy"
|
||||
/>
|
||||
@@ -160,18 +231,26 @@
|
||||
<!-- email alert -->
|
||||
<q-td>
|
||||
<q-checkbox
|
||||
v-if="props.row.alert_template && props.row.alert_template.always_email != null"
|
||||
v-if="
|
||||
props.row.alert_template &&
|
||||
props.row.alert_template.always_email != null
|
||||
"
|
||||
v-model="props.row.alert_template.always_email"
|
||||
disable
|
||||
dense
|
||||
>
|
||||
<q-tooltip> Setting is overridden by alert template: {{ props.row.alert_template.name }} </q-tooltip>
|
||||
<q-tooltip>
|
||||
Setting is overridden by alert template:
|
||||
{{ props.row.alert_template.name }}
|
||||
</q-tooltip>
|
||||
</q-checkbox>
|
||||
|
||||
<q-checkbox
|
||||
v-else
|
||||
dense
|
||||
@update:model-value="editCheck(props.row, { email_alert: !props.row.email_alert })"
|
||||
@update:model-value="
|
||||
editCheck(props.row, { email_alert: !props.row.email_alert })
|
||||
"
|
||||
v-model="props.row.email_alert"
|
||||
:disable="!!props.row.policy"
|
||||
/>
|
||||
@@ -179,18 +258,28 @@
|
||||
<!-- dashboard alert -->
|
||||
<q-td>
|
||||
<q-checkbox
|
||||
v-if="props.row.alert_template && props.row.alert_template.always_alert !== null"
|
||||
v-if="
|
||||
props.row.alert_template &&
|
||||
props.row.alert_template.always_alert !== null
|
||||
"
|
||||
v-model="props.row.alert_template.always_alert"
|
||||
disable
|
||||
dense
|
||||
>
|
||||
<q-tooltip> Setting is overridden by alert template: {{ props.row.alert_template.name }} </q-tooltip>
|
||||
<q-tooltip>
|
||||
Setting is overridden by alert template:
|
||||
{{ props.row.alert_template.name }}
|
||||
</q-tooltip>
|
||||
</q-checkbox>
|
||||
|
||||
<q-checkbox
|
||||
v-else
|
||||
dense
|
||||
@update:model-value="editCheck(props.row, { dashboard_alert: !props.row.dashboard_alert })"
|
||||
@update:model-value="
|
||||
editCheck(props.row, {
|
||||
dashboard_alert: !props.row.dashboard_alert,
|
||||
})
|
||||
"
|
||||
v-model="props.row.dashboard_alert"
|
||||
:disable="!!props.row.policy"
|
||||
/>
|
||||
@@ -210,12 +299,21 @@
|
||||
<!-- status icon -->
|
||||
<q-td v-if="Object.keys(props.row.check_result).length === 0"></q-td>
|
||||
<q-td v-else-if="props.row.check_result.status === 'passing'">
|
||||
<q-icon style="font-size: 1.3rem" color="positive" name="check_circle">
|
||||
<q-icon
|
||||
style="font-size: 1.3rem"
|
||||
color="positive"
|
||||
name="check_circle"
|
||||
>
|
||||
<q-tooltip>Passing</q-tooltip>
|
||||
</q-icon>
|
||||
</q-td>
|
||||
<q-td v-else-if="props.row.check_result.status === 'failing'">
|
||||
<q-icon v-if="getAlertSeverity(props.row) === 'info'" style="font-size: 1.3rem" color="info" name="info">
|
||||
<q-icon
|
||||
v-if="getAlertSeverity(props.row) === 'info'"
|
||||
style="font-size: 1.3rem"
|
||||
color="info"
|
||||
name="info"
|
||||
>
|
||||
<q-tooltip>Informational</q-tooltip>
|
||||
</q-icon>
|
||||
<q-icon
|
||||
@@ -226,7 +324,12 @@
|
||||
>
|
||||
<q-tooltip>Warning</q-tooltip>
|
||||
</q-icon>
|
||||
<q-icon v-else style="font-size: 1.3rem" color="negative" name="error">
|
||||
<q-icon
|
||||
v-else
|
||||
style="font-size: 1.3rem"
|
||||
color="negative"
|
||||
name="error"
|
||||
>
|
||||
<q-tooltip>Error</q-tooltip>
|
||||
</q-icon>
|
||||
</q-td>
|
||||
@@ -235,7 +338,9 @@
|
||||
<q-td>
|
||||
<span>
|
||||
{{ truncateText(props.row.readable_desc, 40) }}
|
||||
<q-tooltip v-if="props.row.readable_desc.length > 40">{{ props.row.readable_desc }}</q-tooltip>
|
||||
<q-tooltip v-if="props.row.readable_desc.length > 40">{{
|
||||
props.row.readable_desc
|
||||
}}</q-tooltip>
|
||||
</span></q-td
|
||||
>
|
||||
<!-- more info -->
|
||||
@@ -249,21 +354,27 @@
|
||||
>
|
||||
|
||||
<span
|
||||
v-if="props.row.check_type === 'ping' && props.row.check_result.id"
|
||||
v-if="
|
||||
props.row.check_type === 'ping' && props.row.check_result.id
|
||||
"
|
||||
style="cursor: pointer; text-decoration: underline"
|
||||
class="text-primary"
|
||||
@click="showPingInfo(props.row)"
|
||||
>Last Output</span
|
||||
>
|
||||
<span
|
||||
v-else-if="props.row.check_type === 'script' && props.row.check_result.id"
|
||||
v-else-if="
|
||||
props.row.check_type === 'script' && props.row.check_result.id
|
||||
"
|
||||
style="cursor: pointer; text-decoration: underline"
|
||||
class="text-primary"
|
||||
@click="showScriptOutput(props.row.check_result)"
|
||||
>Last Output</span
|
||||
>
|
||||
<span
|
||||
v-else-if="props.row.check_type === 'eventlog' && props.row.check_result.id"
|
||||
v-else-if="
|
||||
props.row.check_type === 'eventlog' && props.row.check_result.id
|
||||
"
|
||||
style="cursor: pointer; text-decoration: underline"
|
||||
class="text-primary"
|
||||
@click="showEventInfo(props.row)"
|
||||
@@ -271,14 +382,23 @@
|
||||
>
|
||||
<span
|
||||
v-else-if="
|
||||
props.row.check_type === 'diskspace' || (props.row.check_type === 'winsvc' && props.row.check_result.id)
|
||||
props.row.check_type === 'diskspace' ||
|
||||
(props.row.check_type === 'winsvc' && props.row.check_result.id)
|
||||
"
|
||||
>{{ props.row.check_result.more_info }}</span
|
||||
>
|
||||
</q-td>
|
||||
<q-td>{{ props.row.check_result.last_run ? formatDate(props.row.check_result.last_run) : "Never" }}</q-td>
|
||||
<q-td v-if="props.row.assignedtasks.length > 1">{{ props.row.assignedtasks.length }} Tasks</q-td>
|
||||
<q-td v-else-if="props.row.assignedtasks.length === 1">{{ props.row.assignedtasks[0].name }}</q-td>
|
||||
<q-td>{{
|
||||
props.row.check_result.last_run
|
||||
? formatDate(props.row.check_result.last_run)
|
||||
: "Never"
|
||||
}}</q-td>
|
||||
<q-td v-if="props.row.assignedtasks.length > 1"
|
||||
>{{ props.row.assignedtasks.length }} Tasks</q-td
|
||||
>
|
||||
<q-td v-else-if="props.row.assignedtasks.length === 1">{{
|
||||
props.row.assignedtasks[0].name
|
||||
}}</q-td>
|
||||
<q-td v-else></q-td>
|
||||
</q-tr>
|
||||
</template>
|
||||
@@ -291,7 +411,12 @@
|
||||
import { ref, computed, watch, inject, onMounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import { useQuasar } from "quasar";
|
||||
import { updateCheck, removeCheck, resetCheck, runAgentChecks } from "@/api/checks";
|
||||
import {
|
||||
updateCheck,
|
||||
removeCheck,
|
||||
resetCheck,
|
||||
runAgentChecks,
|
||||
} from "@/api/checks";
|
||||
import { fetchAgentChecks } from "@/api/agents";
|
||||
import { truncateText } from "@/utils/format";
|
||||
import { notifySuccess, notifyWarning } from "@/utils/notify";
|
||||
@@ -315,7 +440,13 @@ const columns = [
|
||||
{ name: "dashboardalert", field: "dashboard_alert", align: "left" },
|
||||
{ name: "policystatus", align: "left" },
|
||||
{ name: "statusicon", align: "left" },
|
||||
{ name: "desc", field: "readable_desc", label: "Description", align: "left", sortable: true },
|
||||
{
|
||||
name: "desc",
|
||||
field: "readable_desc",
|
||||
label: "Description",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "moreinfo",
|
||||
label: "More Info",
|
||||
@@ -330,12 +461,18 @@ const columns = [
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{ name: "assignedtasks", label: "Assigned Tasks", field: "assigned_task", align: "left", sortable: true },
|
||||
{
|
||||
name: "assignedtasks",
|
||||
label: "Assigned Tasks",
|
||||
field: "assigned_task",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
];
|
||||
|
||||
export default {
|
||||
name: "ChecksTab",
|
||||
setup(props) {
|
||||
setup() {
|
||||
// setup vuex
|
||||
const store = useStore();
|
||||
const selectedAgent = computed(() => store.state.selectedRow);
|
||||
@@ -429,7 +566,10 @@ export default {
|
||||
const result = await resetCheck(check.check_result.id);
|
||||
await getChecks();
|
||||
notifySuccess(result);
|
||||
refreshDashboard(false /* clearTreeSelected */, false /* clearSubTable */);
|
||||
refreshDashboard(
|
||||
false /* clearTreeSelected */,
|
||||
false /* clearSubTable */
|
||||
);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
@@ -495,7 +635,7 @@ export default {
|
||||
}).onOk(getChecks);
|
||||
}
|
||||
|
||||
watch(selectedAgent, (newValue, oldValue) => {
|
||||
watch(selectedAgent, (newValue) => {
|
||||
if (newValue) {
|
||||
getChecks();
|
||||
}
|
||||
@@ -537,4 +677,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@@ -2,7 +2,10 @@
|
||||
<div v-if="!selectedAgent" class="q-pa-sm">No agent selected</div>
|
||||
<div v-else>
|
||||
<q-table
|
||||
:table-class="{ 'table-bgcolor': !$q.dark.isActive, 'table-bgcolor-dark': $q.dark.isActive }"
|
||||
:table-class="{
|
||||
'table-bgcolor': !$q.dark.isActive,
|
||||
'table-bgcolor-dark': $q.dark.isActive,
|
||||
}"
|
||||
:rows="history"
|
||||
:columns="columns"
|
||||
:pagination="{ sortBy: 'time', descending: true, rowsPerPage: 0 }"
|
||||
@@ -17,7 +20,14 @@
|
||||
<template v-slot:top>
|
||||
<q-btn dense flat push @click="getHistory" icon="refresh" />
|
||||
<q-space />
|
||||
<q-input v-model="filter" outlined label="Search" dense clearable class="q-pr-sm">
|
||||
<q-input
|
||||
v-model="filter"
|
||||
outlined
|
||||
label="Search"
|
||||
dense
|
||||
clearable
|
||||
class="q-pr-sm"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<q-icon name="search" color="primary" />
|
||||
</template>
|
||||
@@ -80,7 +90,7 @@ const columns = [
|
||||
field: "type",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
format: (val, row) => formatTableColumnText(val),
|
||||
format: (val) => formatTableColumnText(val),
|
||||
},
|
||||
/* {
|
||||
name: "status",
|
||||
@@ -93,13 +103,28 @@ const columns = [
|
||||
{
|
||||
name: "command",
|
||||
label: "Script/Command",
|
||||
field: row => (row.type === "script_run" || row.type === "task_run" ? row.script_name : row.command),
|
||||
field: (row) =>
|
||||
row.type === "script_run" || row.type === "task_run"
|
||||
? row.script_name
|
||||
: row.command,
|
||||
align: "left",
|
||||
sortable: true,
|
||||
format: (val) => truncateText(val, 30),
|
||||
},
|
||||
{
|
||||
name: "username",
|
||||
label: "Initiated By",
|
||||
field: "username",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "output",
|
||||
label: "Output",
|
||||
field: "output",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
format: (val, row) => truncateText(val, 30),
|
||||
},
|
||||
{ name: "username", label: "Initiated By", field: "username", align: "left", sortable: true },
|
||||
{ name: "output", label: "Output", field: "output", align: "left", sortable: true },
|
||||
];
|
||||
|
||||
export default {
|
||||
@@ -126,7 +151,7 @@ export default {
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
watch(selectedAgent, (newValue, oldValue) => {
|
||||
watch(selectedAgent, (newValue) => {
|
||||
if (newValue) {
|
||||
getHistory();
|
||||
}
|
||||
|
@@ -16,8 +16,23 @@
|
||||
no-data-label="No notes"
|
||||
>
|
||||
<template v-slot:top>
|
||||
<q-btn class="q-mr-sm" dense flat push @click="getNotes" icon="refresh" />
|
||||
<q-btn icon="add" label="Add Note" no-caps dense flat push @click="addNote" />
|
||||
<q-btn
|
||||
class="q-mr-sm"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
@click="getNotes"
|
||||
icon="refresh"
|
||||
/>
|
||||
<q-btn
|
||||
icon="add"
|
||||
label="Add Note"
|
||||
no-caps
|
||||
dense
|
||||
flat
|
||||
push
|
||||
@click="addNote"
|
||||
/>
|
||||
<q-space />
|
||||
<export-table-btn :data="notes" :columns="columns" />
|
||||
</template>
|
||||
@@ -31,21 +46,31 @@
|
||||
<q-card-section>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="text-subtitle2">{{ formatDate(props.row.entry_time) }}</div>
|
||||
<div class="text-subtitle2">
|
||||
{{ formatDate(props.row.entry_time) }}
|
||||
</div>
|
||||
<div class="text-caption">{{ props.row.username }}</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<q-btn color="grey-7" round flat icon="more_vert">
|
||||
<q-menu cover auto-close>
|
||||
<q-list dense>
|
||||
<q-item clickable v-close-popup @click="editNote(props.row)">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="editNote(props.row)"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="edit" />
|
||||
</q-item-section>
|
||||
<q-item-section>Edit</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-item clickable v-close-popup @click="deleteNote(props.row)">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="deleteNote(props.row)"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="delete" />
|
||||
</q-item-section>
|
||||
@@ -71,7 +96,12 @@
|
||||
import { ref, computed, watch, onMounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import { useQuasar } from "quasar";
|
||||
import { fetchAgentNotes, editAgentNote, saveAgentNote, removeAgentNote } from "@/api/agents";
|
||||
import {
|
||||
fetchAgentNotes,
|
||||
editAgentNote,
|
||||
saveAgentNote,
|
||||
removeAgentNote,
|
||||
} from "@/api/agents";
|
||||
import { notifySuccess } from "@/utils/notify";
|
||||
|
||||
// ui imports
|
||||
@@ -101,7 +131,7 @@ export default {
|
||||
components: {
|
||||
ExportTableBtn,
|
||||
},
|
||||
setup(props) {
|
||||
setup() {
|
||||
// setup vuex
|
||||
const store = useStore();
|
||||
const selectedAgent = computed(() => store.state.selectedRow);
|
||||
@@ -134,7 +164,7 @@ export default {
|
||||
prompt: {
|
||||
model: noteText,
|
||||
type: "textarea",
|
||||
isValid: val => !!val,
|
||||
isValid: (val) => !!val,
|
||||
},
|
||||
style: "width: 30vw; max-width: 50vw;",
|
||||
ok: { label: "Add" },
|
||||
@@ -142,7 +172,10 @@ export default {
|
||||
}).onOk(async () => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const result = await saveAgentNote({ agent_id: selectedAgent.value, note: noteText.value });
|
||||
const result = await saveAgentNote({
|
||||
agent_id: selectedAgent.value,
|
||||
note: noteText.value,
|
||||
});
|
||||
notifySuccess(result);
|
||||
await getNotes();
|
||||
} catch (e) {
|
||||
@@ -158,12 +191,12 @@ export default {
|
||||
prompt: {
|
||||
model: note.note,
|
||||
type: "textarea",
|
||||
isValid: val => !!val,
|
||||
isValid: (val) => !!val,
|
||||
},
|
||||
style: "width: 30vw; max-width: 50vw;",
|
||||
ok: { label: "Save" },
|
||||
cancel: true,
|
||||
}).onOk(async data => {
|
||||
}).onOk(async (data) => {
|
||||
loading.value = true;
|
||||
try {
|
||||
const result = await editAgentNote(note.pk, { note: data });
|
||||
@@ -194,7 +227,7 @@ export default {
|
||||
});
|
||||
}
|
||||
|
||||
watch(selectedAgent, (newValue, oldValue) => {
|
||||
watch(selectedAgent, (newValue) => {
|
||||
if (newValue) {
|
||||
getNotes();
|
||||
}
|
||||
|
@@ -5,7 +5,10 @@
|
||||
</div>
|
||||
<div v-else>
|
||||
<q-table
|
||||
:table-class="{ 'table-bgcolor': !$q.dark.isActive, 'table-bgcolor-dark': $q.dark.isActive }"
|
||||
:table-class="{
|
||||
'table-bgcolor': !$q.dark.isActive,
|
||||
'table-bgcolor-dark': $q.dark.isActive,
|
||||
}"
|
||||
class="tabs-tbl-sticky"
|
||||
dense
|
||||
:rows="software"
|
||||
@@ -24,12 +27,34 @@
|
||||
</template>
|
||||
|
||||
<template v-slot:top>
|
||||
<q-btn class="q-mr-sm" dense flat push @click="refreshSoftware" icon="refresh" />
|
||||
<q-btn icon="add" label="Install Software" no-caps dense flat push @click="showInstallSoftwareModal" />
|
||||
<q-btn
|
||||
class="q-mr-sm"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
@click="refreshSoftware"
|
||||
icon="refresh"
|
||||
/>
|
||||
<q-btn
|
||||
icon="add"
|
||||
label="Install Software"
|
||||
no-caps
|
||||
dense
|
||||
flat
|
||||
push
|
||||
@click="showInstallSoftwareModal"
|
||||
/>
|
||||
|
||||
<q-space />
|
||||
|
||||
<q-input v-model="filter" outlined label="Search" dense clearable class="q-pr-sm">
|
||||
<q-input
|
||||
v-model="filter"
|
||||
outlined
|
||||
label="Search"
|
||||
dense
|
||||
clearable
|
||||
class="q-pr-sm"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<q-icon name="search" color="primary" />
|
||||
</template>
|
||||
@@ -73,7 +98,7 @@ const columns = [
|
||||
label: "Installed On",
|
||||
field: "install_date",
|
||||
sortable: false,
|
||||
format: (val, row) => {
|
||||
format: (val) => {
|
||||
return val === "01/01/1" || val === "01-1-01" ? "" : val;
|
||||
},
|
||||
},
|
||||
@@ -98,7 +123,7 @@ export default {
|
||||
components: {
|
||||
ExportTableBtn,
|
||||
},
|
||||
setup(props) {
|
||||
setup() {
|
||||
// setup quasar
|
||||
const $q = useQuasar();
|
||||
|
||||
@@ -140,7 +165,7 @@ export default {
|
||||
});
|
||||
}
|
||||
|
||||
watch(selectedAgent, (newValue, oldValue) => {
|
||||
watch(selectedAgent, (newValue) => {
|
||||
if (newValue) {
|
||||
getSoftware();
|
||||
}
|
||||
@@ -170,4 +195,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@@ -1,13 +1,27 @@
|
||||
<template>
|
||||
<div v-if="!selectedAgent" class="q-pa-sm">No agent selected</div>
|
||||
<div v-else-if="!summary && loading" class="q-pa-md flex flex-center">
|
||||
<q-circular-progress indeterminate size="50px" color="primary" class="q-ma-md" />
|
||||
<q-circular-progress
|
||||
indeterminate
|
||||
size="50px"
|
||||
color="primary"
|
||||
class="q-ma-md"
|
||||
/>
|
||||
</div>
|
||||
<div v-else-if="summary" class="q-pa-sm">
|
||||
<q-bar dense style="background-color: transparent">
|
||||
<q-btn dense flat size="md" class="q-mr-sm" icon="refresh" @click="refreshSummary" />
|
||||
<q-btn
|
||||
dense
|
||||
flat
|
||||
size="md"
|
||||
class="q-mr-sm"
|
||||
icon="refresh"
|
||||
@click="refreshSummary"
|
||||
/>
|
||||
<b>{{ summary.hostname }}</b>
|
||||
<span v-if="summary.maintenance_mode"> • <q-badge color="green"> Maintenance Mode </q-badge> </span>
|
||||
<span v-if="summary.maintenance_mode">
|
||||
• <q-badge color="green"> Maintenance Mode </q-badge>
|
||||
</span>
|
||||
• {{ summary.operating_system }} • Agent v{{ summary.version }}
|
||||
<q-space />
|
||||
<q-btn
|
||||
@@ -92,19 +106,43 @@
|
||||
<br />
|
||||
<div v-if="summary.checks.total !== 0">
|
||||
<q-chip v-if="summary.checks.passing" square size="lg">
|
||||
<q-avatar size="lg" square icon="done" color="green" text-color="white" />
|
||||
<q-avatar
|
||||
size="lg"
|
||||
square
|
||||
icon="done"
|
||||
color="green"
|
||||
text-color="white"
|
||||
/>
|
||||
<small>{{ summary.checks.passing }} checks passing</small>
|
||||
</q-chip>
|
||||
<q-chip v-if="summary.checks.failing" square size="lg">
|
||||
<q-avatar size="lg" square icon="cancel" color="red" text-color="white" />
|
||||
<q-avatar
|
||||
size="lg"
|
||||
square
|
||||
icon="cancel"
|
||||
color="red"
|
||||
text-color="white"
|
||||
/>
|
||||
<small>{{ summary.checks.failing }} checks failing</small>
|
||||
</q-chip>
|
||||
<q-chip v-if="summary.checks.warning" square size="lg">
|
||||
<q-avatar size="lg" square icon="warning" color="warning" text-color="white" />
|
||||
<q-avatar
|
||||
size="lg"
|
||||
square
|
||||
icon="warning"
|
||||
color="warning"
|
||||
text-color="white"
|
||||
/>
|
||||
<small>{{ summary.checks.warning }} checks warning</small>
|
||||
</q-chip>
|
||||
<q-chip v-if="summary.checks.info" square size="lg">
|
||||
<q-avatar size="lg" square icon="info" color="info" text-color="white" />
|
||||
<q-avatar
|
||||
size="lg"
|
||||
square
|
||||
icon="info"
|
||||
color="info"
|
||||
text-color="white"
|
||||
/>
|
||||
<small>{{ summary.checks.info }} checks info</small>
|
||||
</q-chip>
|
||||
<span
|
||||
@@ -115,7 +153,8 @@
|
||||
summary.checks.warning === 0 &&
|
||||
summary.checks.info === 0
|
||||
"
|
||||
>{{ summary.checks.total }} checks awaiting first synchronization</span
|
||||
>{{ summary.checks.total }} checks awaiting first
|
||||
synchronization</span
|
||||
>
|
||||
</div>
|
||||
<div v-else>No checks</div>
|
||||
@@ -147,7 +186,12 @@
|
||||
// composition imports
|
||||
import { ref, computed, watch, onMounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import { fetchAgent, refreshAgentWMI, runTakeControl, openAgentWindow } from "@/api/agents";
|
||||
import {
|
||||
fetchAgent,
|
||||
refreshAgentWMI,
|
||||
runTakeControl,
|
||||
openAgentWindow,
|
||||
} from "@/api/agents";
|
||||
import { notifySuccess } from "@/utils/notify";
|
||||
|
||||
// ui imports
|
||||
@@ -158,7 +202,7 @@ export default {
|
||||
components: {
|
||||
AgentActionMenu,
|
||||
},
|
||||
setup(props) {
|
||||
setup() {
|
||||
// vuex setup
|
||||
const store = useStore();
|
||||
const selectedAgent = computed(() => store.state.selectedRow);
|
||||
@@ -185,6 +229,7 @@ export default {
|
||||
|
||||
const entries = Object.entries(summary.value.disks);
|
||||
const ret = [];
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
for (let [k, v] of entries) {
|
||||
ret.push(v);
|
||||
}
|
||||
@@ -210,13 +255,13 @@ export default {
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
watch(selectedAgent, (newValue, oldValue) => {
|
||||
watch(selectedAgent, (newValue) => {
|
||||
if (newValue) {
|
||||
getSummary();
|
||||
}
|
||||
});
|
||||
|
||||
watch(refreshSummaryTab, (newValue, oldValue) => {
|
||||
watch(refreshSummaryTab, (newValue) => {
|
||||
if (newValue && selectedAgent.value) {
|
||||
getSummary();
|
||||
}
|
||||
@@ -245,4 +290,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@@ -6,7 +6,10 @@
|
||||
<div v-else>
|
||||
<q-table
|
||||
dense
|
||||
:table-class="{ 'table-bgcolor': !$q.dark.isActive, 'table-bgcolor-dark': $q.dark.isActive }"
|
||||
:table-class="{
|
||||
'table-bgcolor': !$q.dark.isActive,
|
||||
'table-bgcolor-dark': $q.dark.isActive,
|
||||
}"
|
||||
class="tabs-tbl-sticky"
|
||||
:style="{ 'max-height': tabHeight }"
|
||||
:rows="updates"
|
||||
@@ -21,12 +24,42 @@
|
||||
no-data-label="No Windows Updates"
|
||||
>
|
||||
<template v-slot:top>
|
||||
<q-btn dense flat push @click="getUpdates" icon="refresh" class="q-mr-sm" />
|
||||
<q-btn label="Run Update Scan" dense flat push no-caps @click="updateScan" class="q-mr-sm" />
|
||||
<q-btn label="Install Approved Updates" dense flat push no-caps @click="installUpdates" class="q-mr-sm" />
|
||||
<q-btn
|
||||
dense
|
||||
flat
|
||||
push
|
||||
@click="getUpdates"
|
||||
icon="refresh"
|
||||
class="q-mr-sm"
|
||||
/>
|
||||
<q-btn
|
||||
label="Run Update Scan"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
no-caps
|
||||
@click="updateScan"
|
||||
class="q-mr-sm"
|
||||
/>
|
||||
<q-btn
|
||||
label="Install Approved Updates"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
no-caps
|
||||
@click="installUpdates"
|
||||
class="q-mr-sm"
|
||||
/>
|
||||
<q-space />
|
||||
|
||||
<q-input v-model="filter" outlined label="Search" dense clearable class="q-pr-sm">
|
||||
<q-input
|
||||
v-model="filter"
|
||||
outlined
|
||||
label="Search"
|
||||
dense
|
||||
clearable
|
||||
class="q-pr-sm"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<q-icon name="search" color="primary" />
|
||||
</template>
|
||||
@@ -78,27 +111,55 @@
|
||||
</q-menu>
|
||||
<!-- policy -->
|
||||
<q-td>
|
||||
<q-icon v-if="props.row.action === 'nothing'" name="fiber_manual_record" color="grey">
|
||||
<q-icon
|
||||
v-if="props.row.action === 'nothing'"
|
||||
name="fiber_manual_record"
|
||||
color="grey"
|
||||
>
|
||||
<q-tooltip>Do Nothing</q-tooltip>
|
||||
</q-icon>
|
||||
<q-icon v-else-if="props.row.action === 'approve'" name="fas fa-check" color="primary">
|
||||
<q-icon
|
||||
v-else-if="props.row.action === 'approve'"
|
||||
name="fas fa-check"
|
||||
color="primary"
|
||||
>
|
||||
<q-tooltip>Approve</q-tooltip>
|
||||
</q-icon>
|
||||
<q-icon v-else-if="props.row.action === 'ignore'" name="fas fa-check" color="negative">
|
||||
<q-icon
|
||||
v-else-if="props.row.action === 'ignore'"
|
||||
name="fas fa-check"
|
||||
color="negative"
|
||||
>
|
||||
<q-tooltip>Ignore</q-tooltip>
|
||||
</q-icon>
|
||||
<q-icon v-else-if="props.row.action === 'inherit'" name="fiber_manual_record" color="accent">
|
||||
<q-icon
|
||||
v-else-if="props.row.action === 'inherit'"
|
||||
name="fiber_manual_record"
|
||||
color="accent"
|
||||
>
|
||||
<q-tooltip>Inherit</q-tooltip>
|
||||
</q-icon>
|
||||
</q-td>
|
||||
<q-td>
|
||||
<q-icon v-if="props.row.installed" name="fas fa-check" color="positive">
|
||||
<q-icon
|
||||
v-if="props.row.installed"
|
||||
name="fas fa-check"
|
||||
color="positive"
|
||||
>
|
||||
<q-tooltip>Installed</q-tooltip>
|
||||
</q-icon>
|
||||
<q-icon v-else-if="props.row.action == 'approve'" name="fas fa-tasks" color="primary">
|
||||
<q-icon
|
||||
v-else-if="props.row.action == 'approve'"
|
||||
name="fas fa-tasks"
|
||||
color="primary"
|
||||
>
|
||||
<q-tooltip>Pending</q-tooltip>
|
||||
</q-icon>
|
||||
<q-icon v-else-if="props.row.action == 'ignore'" name="fas fa-ban" color="negative">
|
||||
<q-icon
|
||||
v-else-if="props.row.action == 'ignore'"
|
||||
name="fas fa-ban"
|
||||
color="negative"
|
||||
>
|
||||
<q-tooltip>Ignored</q-tooltip>
|
||||
</q-icon>
|
||||
<q-icon v-else name="fas fa-exclamation" color="warning">
|
||||
@@ -108,9 +169,11 @@
|
||||
<q-td>{{ !props.row.severity ? "Other" : props.row.severity }}</q-td>
|
||||
<q-td>{{ truncateText(props.row.title, 50) }}</q-td>
|
||||
<q-td @click="showUpdateDetails(props.row)">
|
||||
<span style="cursor: pointer; text-decoration: underline" class="text-primary">{{
|
||||
truncateText(props.row.description, 50)
|
||||
}}</span>
|
||||
<span
|
||||
style="cursor: pointer; text-decoration: underline"
|
||||
class="text-primary"
|
||||
>{{ truncateText(props.row.description, 50) }}</span
|
||||
>
|
||||
</q-td>
|
||||
<q-td>{{ formatDate(props.row.date_installed) }}</q-td>
|
||||
</q-tr>
|
||||
@@ -124,7 +187,12 @@
|
||||
import { ref, computed, watch, inject, onMounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import { useQuasar } from "quasar";
|
||||
import { fetchAgentUpdates, editAgentUpdate, runAgentUpdateScan, runAgentUpdateInstall } from "@/api/winupdates";
|
||||
import {
|
||||
fetchAgentUpdates,
|
||||
editAgentUpdate,
|
||||
runAgentUpdateScan,
|
||||
runAgentUpdateInstall,
|
||||
} from "@/api/winupdates";
|
||||
import { notifySuccess } from "@/utils/notify";
|
||||
import { truncateText } from "@/utils/format";
|
||||
|
||||
@@ -176,7 +244,7 @@ const columns = [
|
||||
export default {
|
||||
name: "WindowsUpdates",
|
||||
components: { ExportTableBtn },
|
||||
setup(props) {
|
||||
setup() {
|
||||
// setup vuex
|
||||
const store = useStore();
|
||||
const selectedAgent = computed(() => store.state.selectedRow);
|
||||
@@ -243,7 +311,7 @@ export default {
|
||||
|
||||
function showUpdateDetails(update) {
|
||||
let support_urls = "";
|
||||
update.more_info_urls.forEach(u => {
|
||||
update.more_info_urls.forEach((u) => {
|
||||
support_urls += `<a href='${u}' target='_blank'>${u}</a><br/>`;
|
||||
});
|
||||
let cats = update.categories.join(", ");
|
||||
@@ -259,7 +327,7 @@ export default {
|
||||
});
|
||||
}
|
||||
|
||||
watch(selectedAgent, (newValue, oldValue) => {
|
||||
watch(selectedAgent, (newValue) => {
|
||||
if (newValue) {
|
||||
getUpdates();
|
||||
}
|
||||
|
@@ -4,7 +4,9 @@
|
||||
<div v-for="j in i" :key="j + uid()">
|
||||
<div v-for="(v, k) in j" :key="v + uid()">
|
||||
<span class="text-overline">{{ k }}:</span>
|
||||
<q-badge color="primary" class="q-ml-sm text-caption">{{ v }}</q-badge>
|
||||
<q-badge color="primary" class="q-ml-sm text-caption">{{
|
||||
v
|
||||
}}</q-badge>
|
||||
</div>
|
||||
</div>
|
||||
<q-separator v-if="info.length > 1" />
|
||||
@@ -21,7 +23,7 @@ import { uid } from "quasar";
|
||||
export default {
|
||||
name: "WmiDetail",
|
||||
props: { info: !Object },
|
||||
setup(props) {
|
||||
setup() {
|
||||
// setup vuex
|
||||
const store = useStore();
|
||||
const tabHeight = computed(() => store.state.tabHeight);
|
||||
@@ -33,4 +35,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@@ -5,16 +5,28 @@
|
||||
<div v-else>
|
||||
<div class="row q-pt-sm q-pl-sm">
|
||||
<div class="col-2">
|
||||
<q-select dense options-dense outlined v-model="days" :options="lastDaysOptions" :label="showDays" />
|
||||
<q-select
|
||||
dense
|
||||
options-dense
|
||||
outlined
|
||||
v-model="days"
|
||||
:options="lastDaysOptions"
|
||||
:label="showDays"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-7"></div>
|
||||
<div class="col-3">
|
||||
<code v-if="events">{{ logType }} log total records: {{ events.length }}</code>
|
||||
<code v-if="events"
|
||||
>{{ logType }} log total records: {{ events.length }}</code
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<q-table
|
||||
dense
|
||||
:table-class="{ 'table-bgcolor': !$q.dark.isActive, 'table-bgcolor-dark': $q.dark.isActive }"
|
||||
:table-class="{
|
||||
'table-bgcolor': !$q.dark.isActive,
|
||||
'table-bgcolor-dark': $q.dark.isActive,
|
||||
}"
|
||||
class="remote-bg-tbl-sticky"
|
||||
:rows="events"
|
||||
:columns="columns"
|
||||
@@ -38,15 +50,32 @@
|
||||
@update:model-value="getEventLog"
|
||||
/>
|
||||
<q-radio v-model="logType" color="cyan" val="System" label="System" />
|
||||
<q-radio v-model="logType" color="cyan" val="Security" label="Security" />
|
||||
<q-radio
|
||||
v-model="logType"
|
||||
color="cyan"
|
||||
val="Security"
|
||||
label="Security"
|
||||
/>
|
||||
<q-space />
|
||||
<q-input v-model="filter" style="width: 300px" outlined label="Search" dense clearable>
|
||||
<q-input
|
||||
v-model="filter"
|
||||
style="width: 300px"
|
||||
outlined
|
||||
label="Search"
|
||||
dense
|
||||
clearable
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<q-icon name="search" />
|
||||
</template>
|
||||
</q-input>
|
||||
<!-- file download doesn't work so disabling -->
|
||||
<export-table-btn v-show="false" class="q-ml-sm" :columns="columns" :data="events" />
|
||||
<export-table-btn
|
||||
v-show="false"
|
||||
class="q-ml-sm"
|
||||
:columns="columns"
|
||||
:data="events"
|
||||
/>
|
||||
</template>
|
||||
<template v-slot:body="props">
|
||||
<q-tr :props="props">
|
||||
@@ -55,9 +84,11 @@
|
||||
<q-td>{{ props.row.eventID }}</q-td>
|
||||
<q-td>{{ props.row.time }}</q-td>
|
||||
<q-td @click="showEventMessage(props.row.message)">
|
||||
<span style="cursor: pointer; text-decoration: underline" class="text-primary">{{
|
||||
truncateText(props.row.message, 30)
|
||||
}}</span>
|
||||
<span
|
||||
style="cursor: pointer; text-decoration: underline"
|
||||
class="text-primary"
|
||||
>{{ truncateText(props.row.message, 30) }}</span
|
||||
>
|
||||
</q-td>
|
||||
</q-tr>
|
||||
</template>
|
||||
@@ -77,11 +108,35 @@ import ExportTableBtn from "@/components/ui/ExportTableBtn";
|
||||
|
||||
// static data
|
||||
const columns = [
|
||||
{ name: "eventType", label: "Type", field: "eventType", align: "left", sortable: true },
|
||||
{ name: "source", label: "Source", field: "source", align: "left", sortable: true },
|
||||
{ name: "eventID", label: "Event ID", field: "eventID", align: "left", sortable: true },
|
||||
{
|
||||
name: "eventType",
|
||||
label: "Type",
|
||||
field: "eventType",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "source",
|
||||
label: "Source",
|
||||
field: "source",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "eventID",
|
||||
label: "Event ID",
|
||||
field: "eventID",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{ name: "time", label: "Time", field: "time", align: "left", sortable: true },
|
||||
{ name: "message", label: "Message (click to view full)", field: "message", align: "left", sortable: true },
|
||||
{
|
||||
name: "message",
|
||||
label: "Message (click to view full)",
|
||||
field: "message",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
];
|
||||
|
||||
const lastDaysOptions = [1, 2, 3, 4, 5, 10, 30, 60, 90, 180, 360, 9999];
|
||||
@@ -112,7 +167,11 @@ export default {
|
||||
|
||||
async function getEventLog() {
|
||||
loading.value = true;
|
||||
events.value = await fetchAgentEventLog(props.agent_id, logType.value, days.value);
|
||||
events.value = await fetchAgentEventLog(
|
||||
props.agent_id,
|
||||
logType.value,
|
||||
days.value
|
||||
);
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
|
@@ -1,7 +1,10 @@
|
||||
<template>
|
||||
<q-table
|
||||
dense
|
||||
:table-class="{ 'table-bgcolor': !$q.dark.isActive, 'table-bgcolor-dark': $q.dark.isActive }"
|
||||
:table-class="{
|
||||
'table-bgcolor': !$q.dark.isActive,
|
||||
'table-bgcolor-dark': $q.dark.isActive,
|
||||
}"
|
||||
class="remote-bg-tbl-sticky"
|
||||
:style="{ 'max-height': `${$q.screen.height - 36}px` }"
|
||||
:rows="processes"
|
||||
@@ -14,8 +17,24 @@
|
||||
:loading="loading"
|
||||
>
|
||||
<template v-slot:top>
|
||||
<q-btn v-if="isPolling" dense flat push @click="stopPoll" icon="stop" label="Stop Live Refresh" />
|
||||
<q-btn v-else dense flat push @click="startPoll" icon="play_arrow" label="Resume Live Refresh" />
|
||||
<q-btn
|
||||
v-if="isPolling"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
@click="stopPoll"
|
||||
icon="stop"
|
||||
label="Stop Live Refresh"
|
||||
/>
|
||||
<q-btn
|
||||
v-else
|
||||
dense
|
||||
flat
|
||||
push
|
||||
@click="startPoll"
|
||||
icon="play_arrow"
|
||||
label="Resume Live Refresh"
|
||||
/>
|
||||
|
||||
<q-space />
|
||||
|
||||
@@ -29,10 +48,23 @@
|
||||
size="sm"
|
||||
color="grey"
|
||||
/>
|
||||
<q-btn dense push icon="add" size="sm" color="grey" @click="pollIntervalChanged('add')" />
|
||||
<q-btn
|
||||
dense
|
||||
push
|
||||
icon="add"
|
||||
size="sm"
|
||||
color="grey"
|
||||
@click="pollIntervalChanged('add')"
|
||||
/>
|
||||
</div>
|
||||
<div class="text-overline">
|
||||
<q-badge align="middle" size="sm" class="text-h6" color="blue" :label="pollInterval" />
|
||||
<q-badge
|
||||
align="middle"
|
||||
size="sm"
|
||||
class="text-h6"
|
||||
color="blue"
|
||||
:label="pollInterval"
|
||||
/>
|
||||
Refresh interval (seconds)
|
||||
</div>
|
||||
|
||||
@@ -43,13 +75,21 @@
|
||||
</template>
|
||||
</q-input>
|
||||
<!-- file download doesn't work so disabling -->
|
||||
<export-table-btn v-show="false" class="q-ml-sm" :columns="columns" :data="processes" />
|
||||
<export-table-btn
|
||||
v-show="false"
|
||||
class="q-ml-sm"
|
||||
:columns="columns"
|
||||
:data="processes"
|
||||
/>
|
||||
</template>
|
||||
<template v-slot:body="props">
|
||||
<q-tr :props="props" class="cursor-pointer">
|
||||
<q-menu context-menu auto-close>
|
||||
<q-list dense style="min-width: 200px">
|
||||
<q-item clickable @click="killProcess(props.row.pid, props.row.name)">
|
||||
<q-item
|
||||
clickable
|
||||
@click="killProcess(props.row.pid, props.row.name)"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="fas fa-trash-alt" size="xs" />
|
||||
</q-item-section>
|
||||
@@ -73,7 +113,11 @@
|
||||
|
||||
<script>
|
||||
import { ref, computed, onMounted, onBeforeUnmount } from "vue";
|
||||
import { fetchAgent, fetchAgentProcesses, killAgentProcess } from "@/api/agents";
|
||||
import {
|
||||
fetchAgent,
|
||||
fetchAgentProcesses,
|
||||
killAgentProcess,
|
||||
} from "@/api/agents";
|
||||
import { bytes2Human } from "@/utils/format";
|
||||
import { notifySuccess } from "@/utils/notify";
|
||||
|
||||
@@ -94,7 +138,7 @@ const columns = [
|
||||
field: "cpu_percent",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
sort: (a, b, rowA, rowB) => parseFloat(b) < parseFloat(a),
|
||||
sort: (a, b) => parseFloat(b) < parseFloat(a),
|
||||
},
|
||||
{
|
||||
name: "membytes",
|
||||
@@ -177,7 +221,7 @@ export default {
|
||||
}, pollInterval.value * 1000);
|
||||
}
|
||||
|
||||
async function killProcess(pid, name) {
|
||||
async function killProcess(pid) {
|
||||
loading.value = true;
|
||||
let result = "";
|
||||
try {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<q-dialog ref="dialogRef" @hide="onDialogHide">
|
||||
<q-card style="width: 600px; max-width: 80vw">
|
||||
<q-bar>
|
||||
@@ -23,7 +23,9 @@
|
||||
<div class="row">
|
||||
<div class="col-3">Description:</div>
|
||||
<div class="col-9">
|
||||
<q-field outlined :color="$q.dark.isActive ? 'white' : 'black'">{{ service.description }}</q-field>
|
||||
<q-field outlined :color="$q.dark.isActive ? 'white' : 'black'">{{
|
||||
service.description
|
||||
}}</q-field>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
@@ -61,7 +63,10 @@
|
||||
<q-btn-group color="primary" push>
|
||||
<q-btn label="Start" @click="sendServiceAction(service, 'start')" />
|
||||
<q-btn label="Stop" @click="sendServiceAction(service, 'stop')" />
|
||||
<q-btn label="Restart" @click="sendServiceAction(service, 'restart')" />
|
||||
<q-btn
|
||||
label="Restart"
|
||||
@click="sendServiceAction(service, 'restart')"
|
||||
/>
|
||||
</q-btn-group>
|
||||
</div>
|
||||
</q-card-section>
|
||||
@@ -86,7 +91,10 @@
|
||||
// composition imports
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import { useDialogPluginComponent } from "quasar";
|
||||
import { editAgentServiceStartType, sendAgentServiceAction } from "@/api/services";
|
||||
import {
|
||||
editAgentServiceStartType,
|
||||
sendAgentServiceAction,
|
||||
} from "@/api/services";
|
||||
import { notifySuccess } from "@/utils/notify";
|
||||
|
||||
// static data
|
||||
@@ -124,7 +132,10 @@ export default {
|
||||
const loading = ref(false);
|
||||
|
||||
const startupTypeEdited = computed(() => {
|
||||
if (props.service.start_type.toLowerCase() === "automatic" && props.service.autodelay)
|
||||
if (
|
||||
props.service.start_type.toLowerCase() === "automatic" &&
|
||||
props.service.autodelay
|
||||
)
|
||||
return startupType.value !== "autodelay";
|
||||
else return props.service.start_type.toLowerCase() !== startupType.value;
|
||||
});
|
||||
@@ -132,7 +143,11 @@ export default {
|
||||
async function sendServiceAction(service, action) {
|
||||
loading.value = true;
|
||||
try {
|
||||
const result = await sendAgentServiceAction(props.agent_id, service.name, { sv_action: action });
|
||||
const result = await sendAgentServiceAction(
|
||||
props.agent_id,
|
||||
service.name,
|
||||
{ sv_action: action }
|
||||
);
|
||||
notifySuccess(result);
|
||||
onDialogOK();
|
||||
} catch (e) {
|
||||
@@ -143,12 +158,17 @@ export default {
|
||||
|
||||
async function editServiceStartup() {
|
||||
const data = {
|
||||
startType: startupType.value === "automatic" ? "auto" : startupType.value,
|
||||
startType:
|
||||
startupType.value === "automatic" ? "auto" : startupType.value,
|
||||
};
|
||||
|
||||
loading.value = true;
|
||||
try {
|
||||
const result = await editAgentServiceStartType(props.agent_id, props.service.name, data);
|
||||
const result = await editAgentServiceStartType(
|
||||
props.agent_id,
|
||||
props.service.name,
|
||||
data
|
||||
);
|
||||
notifySuccess(result);
|
||||
onDialogOK();
|
||||
} catch (e) {
|
||||
@@ -158,7 +178,10 @@ export default {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (props.service.start_type.toLowerCase() === "automatic" && props.service.autodelay)
|
||||
if (
|
||||
props.service.start_type.toLowerCase() === "automatic" &&
|
||||
props.service.autodelay
|
||||
)
|
||||
startupType.value = "autodelay";
|
||||
else startupType.value = props.service.start_type.toLowerCase();
|
||||
});
|
||||
|
@@ -5,7 +5,10 @@
|
||||
<q-table
|
||||
v-else
|
||||
dense
|
||||
:table-class="{ 'table-bgcolor': !$q.dark.isActive, 'table-bgcolor-dark': $q.dark.isActive }"
|
||||
:table-class="{
|
||||
'table-bgcolor': !$q.dark.isActive,
|
||||
'table-bgcolor-dark': $q.dark.isActive,
|
||||
}"
|
||||
class="remote-bg-tbl-sticky"
|
||||
:style="{ 'max-height': `${$q.screen.height - 36}px` }"
|
||||
:rows="services"
|
||||
@@ -26,10 +29,19 @@
|
||||
</template>
|
||||
</q-input>
|
||||
<!-- file download doesn't work so disabling -->
|
||||
<export-table-btn v-show="false" class="q-ml-sm" :columns="columns" :data="services" />
|
||||
<export-table-btn
|
||||
v-show="false"
|
||||
class="q-ml-sm"
|
||||
:columns="columns"
|
||||
:data="services"
|
||||
/>
|
||||
</template>
|
||||
<template v-slot:body="props">
|
||||
<q-tr :props="props" class="cursor-pointer" @dblclick="showServiceDetail(props.row)">
|
||||
<q-tr
|
||||
:props="props"
|
||||
class="cursor-pointer"
|
||||
@dblclick="showServiceDetail(props.row)"
|
||||
>
|
||||
<q-menu context-menu auto-close>
|
||||
<q-list dense style="min-width: 200px">
|
||||
<q-item clickable @click="sendServiceAction(props.row, 'start')">
|
||||
@@ -57,13 +69,18 @@
|
||||
</q-td>
|
||||
<q-td key="name" :props="props">{{ props.row.name }}</q-td>
|
||||
<q-td key="start_type" :props="props">{{
|
||||
props.row.start_type.toLowerCase() === "automatic" && props.row.autodelay
|
||||
props.row.start_type.toLowerCase() === "automatic" &&
|
||||
props.row.autodelay
|
||||
? `${props.row.start_type} (Delayed)`
|
||||
: `${props.row.start_type}`
|
||||
}}</q-td>
|
||||
<q-td key="pid" :props="props">{{ props.row.pid === 0 ? "" : props.row.pid }}</q-td>
|
||||
<q-td key="pid" :props="props">{{
|
||||
props.row.pid === 0 ? "" : props.row.pid
|
||||
}}</q-td>
|
||||
<q-td key="status" :props="props">{{ props.row.status }}</q-td>
|
||||
<q-td key="username" :props="props">{{ props.row.username ? props.row.username : "LocalSystem" }}</q-td>
|
||||
<q-td key="username" :props="props">{{
|
||||
props.row.username ? props.row.username : "LocalSystem"
|
||||
}}</q-td>
|
||||
</q-tr>
|
||||
</template>
|
||||
</q-table>
|
||||
@@ -185,7 +202,11 @@ export default {
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const result = await sendAgentServiceAction(props.agent_id, service.name, { sv_action: action });
|
||||
const result = await sendAgentServiceAction(
|
||||
props.agent_id,
|
||||
service.name,
|
||||
{ sv_action: action }
|
||||
);
|
||||
notifySuccess(result);
|
||||
await getServices();
|
||||
} catch (e) {
|
||||
|
@@ -3,7 +3,15 @@
|
||||
<div class="q-dialog-plugin" style="width: 90vw; max-width: 90vw">
|
||||
<q-card>
|
||||
<q-bar>
|
||||
<q-btn ref="refresh" @click="refresh" class="q-mr-sm" dense flat push icon="refresh" />Automation Manager
|
||||
<q-btn
|
||||
ref="refresh"
|
||||
@click="refresh"
|
||||
class="q-mr-sm"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
icon="refresh"
|
||||
/>Automation Manager
|
||||
<q-space />
|
||||
<q-btn dense flat icon="close" v-close-popup>
|
||||
<q-tooltip class="bg-white text-primary">Close</q-tooltip>
|
||||
@@ -11,7 +19,16 @@
|
||||
</q-bar>
|
||||
<q-card-section>
|
||||
<div class="q-gutter-sm">
|
||||
<q-btn label="New" dense flat push unelevated no-caps icon="add" @click="showAddPolicyForm" />
|
||||
<q-btn
|
||||
label="New"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
unelevated
|
||||
no-caps
|
||||
icon="add"
|
||||
@click="showAddPolicyForm"
|
||||
/>
|
||||
<q-btn
|
||||
label="Policy Overview"
|
||||
dense
|
||||
@@ -25,7 +42,10 @@
|
||||
</div>
|
||||
<div class="scroll" style="min-height: 35vh; max-height: 35vh">
|
||||
<q-table
|
||||
:table-class="{ 'table-bgcolor': !$q.dark.isActive, 'table-bgcolor-dark': $q.dark.isActive }"
|
||||
:table-class="{
|
||||
'table-bgcolor': !$q.dark.isActive,
|
||||
'table-bgcolor-dark': $q.dark.isActive,
|
||||
}"
|
||||
class="tabs-tbl-sticky"
|
||||
:rows="policies"
|
||||
:columns="columns"
|
||||
@@ -50,7 +70,10 @@
|
||||
<template v-slot:header-cell-enforced="props">
|
||||
<q-th :props="props" auto-width>
|
||||
<q-icon name="security" size="1.5em">
|
||||
<q-tooltip>Enforce Policy (Will override Agent tasks/checks)</q-tooltip>
|
||||
<q-tooltip
|
||||
>Enforce Policy (Will override Agent
|
||||
tasks/checks)</q-tooltip
|
||||
>
|
||||
</q-icon>
|
||||
</q-th>
|
||||
</template>
|
||||
@@ -68,21 +91,33 @@
|
||||
<!-- context menu -->
|
||||
<q-menu context-menu>
|
||||
<q-list dense style="min-width: 200px">
|
||||
<q-item clickable v-close-popup @click="showEditPolicyForm(props.row)">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showEditPolicyForm(props.row)"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="edit" />
|
||||
</q-item-section>
|
||||
<q-item-section>Edit</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-item clickable v-close-popup @click="showCopyPolicyForm(props.row)">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showCopyPolicyForm(props.row)"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="content_copy" />
|
||||
</q-item-section>
|
||||
<q-item-section>Copy</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-item clickable v-close-popup @click="deletePolicy(props.row)">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="deletePolicy(props.row)"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="delete" />
|
||||
</q-item-section>
|
||||
@@ -91,32 +126,52 @@
|
||||
|
||||
<q-separator></q-separator>
|
||||
|
||||
<q-item clickable v-close-popup @click="showRelations(props.row)">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showRelations(props.row)"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="account_tree" />
|
||||
</q-item-section>
|
||||
<q-item-section>Show Relations</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-item clickable v-close-popup @click="showPolicyExclusions(props.row)">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showPolicyExclusions(props.row)"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="rule" />
|
||||
</q-item-section>
|
||||
<q-item-section>Policy Exclusions</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-item clickable v-close-popup @click="showPatchPolicyForm(props.row)">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showPatchPolicyForm(props.row)"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="system_update" />
|
||||
</q-item-section>
|
||||
<q-item-section>{{ patchPolicyText(props.row) }}</q-item-section>
|
||||
<q-item-section>{{
|
||||
patchPolicyText(props.row)
|
||||
}}</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-item clickable v-close-popup @click="showAlertTemplateAdd(props.row)">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showAlertTemplateAdd(props.row)"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="warning" />
|
||||
</q-item-section>
|
||||
<q-item-section>{{ alertTemplateText(props.row) }}</q-item-section>
|
||||
<q-item-section>{{
|
||||
alertTemplateText(props.row)
|
||||
}}</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-separator></q-separator>
|
||||
@@ -138,16 +193,26 @@
|
||||
<q-td>
|
||||
<q-checkbox
|
||||
dense
|
||||
@update:model-value="toggleCheckbox(props.row, 'Enforced')"
|
||||
@update:model-value="
|
||||
toggleCheckbox(props.row, 'Enforced')
|
||||
"
|
||||
v-model="props.row.enforced"
|
||||
/>
|
||||
</q-td>
|
||||
<q-td>
|
||||
{{ props.row.name }}
|
||||
<q-chip v-if="props.row.default_server_policy" color="primary" text-color="white" size="sm"
|
||||
<q-chip
|
||||
v-if="props.row.default_server_policy"
|
||||
color="primary"
|
||||
text-color="white"
|
||||
size="sm"
|
||||
>Default Server</q-chip
|
||||
>
|
||||
<q-chip v-if="props.row.default_workstation_policy" color="primary" text-color="white" size="sm"
|
||||
<q-chip
|
||||
v-if="props.row.default_workstation_policy"
|
||||
color="primary"
|
||||
text-color="white"
|
||||
size="sm"
|
||||
>Default Workstation</q-chip
|
||||
>
|
||||
</q-td>
|
||||
@@ -191,7 +256,11 @@
|
||||
>
|
||||
</q-td>
|
||||
<q-td>
|
||||
<q-icon name="content_copy" size="1.5em" @click="showCopyPolicyForm(props.row)">
|
||||
<q-icon
|
||||
name="content_copy"
|
||||
size="1.5em"
|
||||
@click="showCopyPolicyForm(props.row)"
|
||||
>
|
||||
<q-tooltip>Create a copy of this policy</q-tooltip>
|
||||
</q-icon>
|
||||
</q-td>
|
||||
@@ -220,12 +289,18 @@
|
||||
<q-tab-panels v-model="subtab" :animated="false">
|
||||
<q-tab-panel name="checks">
|
||||
<div class="scroll" style="min-height: 25vh; max-height: 25vh">
|
||||
<PolicyChecksTab v-if="!!selectedPolicy" :selectedPolicy="selectedPolicy.id" />
|
||||
<PolicyChecksTab
|
||||
v-if="!!selectedPolicy"
|
||||
:selectedPolicy="selectedPolicy.id"
|
||||
/>
|
||||
</div>
|
||||
</q-tab-panel>
|
||||
<q-tab-panel name="tasks">
|
||||
<div class="scroll" style="min-height: 25vh; max-height: 25vh">
|
||||
<PolicyAutomatedTasksTab v-if="!!selectedPolicy" :selectedPolicy="selectedPolicy.id" />
|
||||
<PolicyAutomatedTasksTab
|
||||
v-if="!!selectedPolicy"
|
||||
:selectedPolicy="selectedPolicy.id"
|
||||
/>
|
||||
</div>
|
||||
</q-tab-panel>
|
||||
</q-tab-panels>
|
||||
@@ -259,7 +334,12 @@ export default {
|
||||
selectedPolicy: null,
|
||||
columns: [
|
||||
{ name: "active", label: "Active", field: "active", align: "left" },
|
||||
{ name: "enforced", label: "Enforced", field: "enforced", align: "left" },
|
||||
{
|
||||
name: "enforced",
|
||||
label: "Enforced",
|
||||
field: "enforced",
|
||||
align: "left",
|
||||
},
|
||||
{
|
||||
name: "name",
|
||||
label: "Name",
|
||||
@@ -315,11 +395,11 @@ export default {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.get("/automation/policies/")
|
||||
.then(r => {
|
||||
.then((r) => {
|
||||
this.policies = r.data;
|
||||
this.$q.loading.hide();
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
@@ -341,13 +421,13 @@ export default {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.delete(`/automation/policies/${policy.id}/`)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.refresh();
|
||||
this.$q.loading.hide();
|
||||
this.notifySuccess("Policy was deleted!");
|
||||
this.$store.dispatch("loadTree");
|
||||
})
|
||||
.catch(error => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
});
|
||||
@@ -365,7 +445,7 @@ export default {
|
||||
component: PolicyOverview,
|
||||
});
|
||||
},
|
||||
showAddPolicyForm(policy = undefined) {
|
||||
showAddPolicyForm() {
|
||||
this.$q
|
||||
.dialog({
|
||||
component: PolicyForm,
|
||||
@@ -374,7 +454,7 @@ export default {
|
||||
this.refresh();
|
||||
});
|
||||
},
|
||||
showCopyPolicyForm(policy = undefined) {
|
||||
showCopyPolicyForm(policy) {
|
||||
this.$q
|
||||
.dialog({
|
||||
component: PolicyForm,
|
||||
@@ -416,7 +496,10 @@ export default {
|
||||
.dialog({
|
||||
component: DialogWrapper,
|
||||
componentProps: {
|
||||
title: policy.winupdatepolicy.length > 0 ? "Edit Patch Policy" : "Add Patch Policy",
|
||||
title:
|
||||
policy.winupdatepolicy.length > 0
|
||||
? "Edit Patch Policy"
|
||||
: "Add Patch Policy",
|
||||
vuecomponent: PatchPolicyForm,
|
||||
componentProps: {
|
||||
policy: policy,
|
||||
@@ -450,32 +533,41 @@ export default {
|
||||
};
|
||||
|
||||
if (type === "Active") {
|
||||
text = !policy.active ? "Policy enabled successfully" : "Policy disabled successfully";
|
||||
text = !policy.active
|
||||
? "Policy enabled successfully"
|
||||
: "Policy disabled successfully";
|
||||
data["active"] = !policy.active;
|
||||
} else if (type === "Enforced") {
|
||||
text = !policy.enforced ? "Policy enforced successfully" : "Policy enforcement disabled";
|
||||
text = !policy.enforced
|
||||
? "Policy enforced successfully"
|
||||
: "Policy enforcement disabled";
|
||||
data["enforced"] = !policy.enforced;
|
||||
}
|
||||
|
||||
this.$axios
|
||||
.put(`/automation/policies/${data.id}/`, data)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.refresh();
|
||||
this.$q.loading.hide();
|
||||
this.notifySuccess(text);
|
||||
})
|
||||
.catch(error => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
patchPolicyText(policy) {
|
||||
return policy.winupdatepolicy.length > 0 ? "Modify Patch Policy" : "Create Patch Policy";
|
||||
return policy.winupdatepolicy.length > 0
|
||||
? "Modify Patch Policy"
|
||||
: "Create Patch Policy";
|
||||
},
|
||||
alertTemplateText(policy) {
|
||||
return policy.alert_template ? "Modify Alert Template" : "Assign Alert Template";
|
||||
return policy.alert_template
|
||||
? "Modify Alert Template"
|
||||
: "Assign Alert Template";
|
||||
},
|
||||
rowSelectedClass(id, selectedPolicy) {
|
||||
if (selectedPolicy && selectedPolicy.id === id) return this.$q.dark.isActive ? "highlight-dark" : "highlight";
|
||||
if (selectedPolicy && selectedPolicy.id === id)
|
||||
return this.$q.dark.isActive ? "highlight-dark" : "highlight";
|
||||
},
|
||||
show() {
|
||||
this.$refs.dialog.show();
|
||||
|
@@ -1,10 +1,30 @@
|
||||
<template>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<q-btn v-if="!!selectedPolicy" class="q-mr-sm" dense flat push @click="getTasks" icon="refresh" />
|
||||
<q-btn v-if="!!selectedPolicy" icon="add" label="Add Task" no-caps dense flat push @click="showAddTask" />
|
||||
<q-btn
|
||||
v-if="!!selectedPolicy"
|
||||
class="q-mr-sm"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
@click="getTasks"
|
||||
icon="refresh"
|
||||
/>
|
||||
<q-btn
|
||||
v-if="!!selectedPolicy"
|
||||
icon="add"
|
||||
label="Add Task"
|
||||
no-caps
|
||||
dense
|
||||
flat
|
||||
push
|
||||
@click="showAddTask"
|
||||
/>
|
||||
<q-table
|
||||
:table-class="{ 'table-bgcolor': !$q.dark.isActive, 'table-bgcolor-dark': $q.dark.isActive }"
|
||||
:table-class="{
|
||||
'table-bgcolor': !$q.dark.isActive,
|
||||
'table-bgcolor-dark': $q.dark.isActive,
|
||||
}"
|
||||
class="tabs-tbl-sticky"
|
||||
:rows="tasks"
|
||||
:columns="columns"
|
||||
@@ -19,7 +39,9 @@
|
||||
<!-- No data Slot -->
|
||||
<template v-slot:no-data>
|
||||
<div class="full-width row flex-center q-gutter-sm">
|
||||
<span v-if="!selectedPolicy">Click on a policy to see the tasks</span>
|
||||
<span v-if="!selectedPolicy"
|
||||
>Click on a policy to see the tasks</span
|
||||
>
|
||||
<span v-else>There are no tasks added to this policy</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -62,7 +84,7 @@
|
||||
</template>
|
||||
|
||||
<!-- body slots -->
|
||||
<template v-slot:body="props" :props="props">
|
||||
<template v-slot:body="props">
|
||||
<q-tr class="cursor-pointer" @dblclick="showEditTask(props.row)">
|
||||
<!-- context menu -->
|
||||
<q-menu context-menu>
|
||||
@@ -73,7 +95,11 @@
|
||||
</q-item-section>
|
||||
<q-item-section>Run task now</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable v-close-popup @click="showEditTask(props.row)">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showEditTask(props.row)"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="edit" />
|
||||
</q-item-section>
|
||||
@@ -102,7 +128,9 @@
|
||||
<q-td>
|
||||
<q-checkbox
|
||||
dense
|
||||
@update:model-value="editTask(props.row, { enabled: !props.row.enabled })"
|
||||
@update:model-value="
|
||||
editTask(props.row, { enabled: !props.row.enabled })
|
||||
"
|
||||
v-model="props.row.enabled"
|
||||
/>
|
||||
</q-td>
|
||||
@@ -110,7 +138,9 @@
|
||||
<q-td>
|
||||
<q-checkbox
|
||||
dense
|
||||
@update:model-value="editTask(props.row, { text_alert: !props.row.text_alert })"
|
||||
@update:model-value="
|
||||
editTask(props.row, { text_alert: !props.row.text_alert })
|
||||
"
|
||||
v-model="props.row.text_alert"
|
||||
/>
|
||||
</q-td>
|
||||
@@ -118,7 +148,9 @@
|
||||
<q-td>
|
||||
<q-checkbox
|
||||
dense
|
||||
@update:model-value="editTask(props.row, { email_alert: !props.row.email_alert })"
|
||||
@update:model-value="
|
||||
editTask(props.row, { email_alert: !props.row.email_alert })
|
||||
"
|
||||
v-model="props.row.email_alert"
|
||||
/>
|
||||
</q-td>
|
||||
@@ -126,14 +158,24 @@
|
||||
<q-td>
|
||||
<q-checkbox
|
||||
dense
|
||||
@update:model-value="editTask(props.row, { dashboard_alert: !props.row.dashboard_alert })"
|
||||
@update:model-value="
|
||||
editTask(props.row, {
|
||||
dashboard_alert: !props.row.dashboard_alert,
|
||||
})
|
||||
"
|
||||
v-model="props.row.dashboard_alert"
|
||||
/>
|
||||
</q-td>
|
||||
<!-- is collector task -->
|
||||
<q-td>
|
||||
<q-icon v-if="!!props.row.custom_field" style="font-size: 1.3rem" name="check">
|
||||
<q-tooltip>The task updates a custom field on the agent</q-tooltip>
|
||||
<q-icon
|
||||
v-if="!!props.row.custom_field"
|
||||
style="font-size: 1.3rem"
|
||||
name="check"
|
||||
>
|
||||
<q-tooltip
|
||||
>The task updates a custom field on the agent</q-tooltip
|
||||
>
|
||||
</q-icon>
|
||||
</q-td>
|
||||
<q-td>{{ props.row.name }}</q-td>
|
||||
@@ -173,8 +215,20 @@ export default {
|
||||
{ name: "smsalert", field: "text_alert", align: "left" },
|
||||
{ name: "emailalert", field: "email_alert", align: "left" },
|
||||
{ name: "dashboardalert", field: "dashboard_alert", align: "left" },
|
||||
{ name: "collector", label: "Collector", field: "custom_field", align: "left", sortable: true },
|
||||
{ name: "name", label: "Name", field: "name", align: "left", sortable: true },
|
||||
{
|
||||
name: "collector",
|
||||
label: "Collector",
|
||||
field: "custom_field",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "name",
|
||||
label: "Name",
|
||||
field: "name",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "schedule",
|
||||
label: "Schedule",
|
||||
@@ -214,23 +268,23 @@ export default {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.get(`/automation/policies/${this.selectedPolicy}/tasks/`)
|
||||
.then(r => {
|
||||
.then((r) => {
|
||||
this.tasks = r.data;
|
||||
this.$q.loading.hide();
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
editTask(task, data) {
|
||||
this.$axios
|
||||
.put(`/tasks/${task.id}/`, data)
|
||||
.then(r => {
|
||||
.then((r) => {
|
||||
this.$q.loading.hide();
|
||||
this.notifySuccess(r.data);
|
||||
this.getTasks();
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
@@ -266,18 +320,20 @@ export default {
|
||||
},
|
||||
runTask(task) {
|
||||
if (!task.enabled) {
|
||||
this.notifyError("Task cannot be run when it's disabled. Enable it first.");
|
||||
this.notifyError(
|
||||
"Task cannot be run when it's disabled. Enable it first."
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.post(`/automation/tasks/${task.id}/run/`)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.$q.loading.hide();
|
||||
this.notifySuccess("The task was initated on all affected agents");
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
@@ -293,12 +349,12 @@ export default {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.delete(`/tasks/${task.id}/`)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.getTasks();
|
||||
this.$q.loading.hide();
|
||||
this.notifySuccess("Task was deleted successfully");
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
});
|
||||
@@ -309,4 +365,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@@ -1,8 +1,23 @@
|
||||
<template>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<q-btn v-if="!!selectedPolicy" class="q-mr-sm" dense flat push @click="getChecks" icon="refresh" />
|
||||
<q-btn-dropdown v-if="!!selectedPolicy" icon="add" label="New" no-caps dense flat>
|
||||
<q-btn
|
||||
v-if="!!selectedPolicy"
|
||||
class="q-mr-sm"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
@click="getChecks"
|
||||
icon="refresh"
|
||||
/>
|
||||
<q-btn-dropdown
|
||||
v-if="!!selectedPolicy"
|
||||
icon="add"
|
||||
label="New"
|
||||
no-caps
|
||||
dense
|
||||
flat
|
||||
>
|
||||
<q-list dense style="min-width: 200px">
|
||||
<q-item clickable v-close-popup @click="showCheckModal('diskspace')">
|
||||
<q-item-section side>
|
||||
@@ -50,7 +65,10 @@
|
||||
</q-btn-dropdown>
|
||||
|
||||
<q-table
|
||||
:table-class="{ 'table-bgcolor': !$q.dark.isActive, 'table-bgcolor-dark': $q.dark.isActive }"
|
||||
:table-class="{
|
||||
'table-bgcolor': !$q.dark.isActive,
|
||||
'table-bgcolor-dark': $q.dark.isActive,
|
||||
}"
|
||||
class="tabs-tbl-sticky"
|
||||
:rows="checks"
|
||||
:columns="columns"
|
||||
@@ -65,7 +83,9 @@
|
||||
<!-- No data Slot -->
|
||||
<template v-slot:no-data>
|
||||
<div class="full-width row flex-center q-gutter-sm">
|
||||
<span v-if="!selectedPolicy">Click on a policy to see the checks</span>
|
||||
<span v-if="!selectedPolicy"
|
||||
>Click on a policy to see the checks</span
|
||||
>
|
||||
<span v-else>There are no checks added to this policy</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -96,11 +116,19 @@
|
||||
</template>
|
||||
<!-- body slots -->
|
||||
<template v-slot:body="props">
|
||||
<q-tr :props="props" class="cursor-pointer" @dblclick="showCheckModal(props.row.check_type, props.row)">
|
||||
<q-tr
|
||||
:props="props"
|
||||
class="cursor-pointer"
|
||||
@dblclick="showCheckModal(props.row.check_type, props.row)"
|
||||
>
|
||||
<!-- context menu -->
|
||||
<q-menu context-menu>
|
||||
<q-list dense style="min-width: 200px">
|
||||
<q-item clickable v-close-popup @click="showCheckModal(props.row.check_type, props.row)">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showCheckModal(props.row.check_type, props.row)"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="edit" />
|
||||
</q-item-section>
|
||||
@@ -115,7 +143,11 @@
|
||||
|
||||
<q-separator></q-separator>
|
||||
|
||||
<q-item clickable v-close-popup @click="showPolicyStatus(props.row)">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showPolicyStatus(props.row)"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="sync" />
|
||||
</q-item-section>
|
||||
@@ -133,21 +165,31 @@
|
||||
<q-td>
|
||||
<q-checkbox
|
||||
dense
|
||||
@update:model-value="checkAlert(props.row.id, 'Text', props.row.text_alert)"
|
||||
@update:model-value="
|
||||
checkAlert(props.row.id, 'Text', props.row.text_alert)
|
||||
"
|
||||
v-model="props.row.text_alert"
|
||||
/>
|
||||
</q-td>
|
||||
<q-td>
|
||||
<q-checkbox
|
||||
dense
|
||||
@update:model-value="checkAlert(props.row.id, 'Email', props.row.email_alert)"
|
||||
@update:model-value="
|
||||
checkAlert(props.row.id, 'Email', props.row.email_alert)
|
||||
"
|
||||
v-model="props.row.email_alert"
|
||||
/>
|
||||
</q-td>
|
||||
<q-td>
|
||||
<q-checkbox
|
||||
dense
|
||||
@update:model-value="checkAlert(props.row.id, 'Dashboard', props.row.dashboard_alert)"
|
||||
@update:model-value="
|
||||
checkAlert(
|
||||
props.row.id,
|
||||
'Dashboard',
|
||||
props.row.dashboard_alert
|
||||
)
|
||||
"
|
||||
v-model="props.row.dashboard_alert"
|
||||
/>
|
||||
</q-td>
|
||||
@@ -160,8 +202,12 @@
|
||||
>See Status</span
|
||||
>
|
||||
</q-td>
|
||||
<q-td v-if="props.row.assignedtasks.length > 1">{{ props.row.assignedtasks.length }} Tasks</q-td>
|
||||
<q-td v-else-if="props.row.assignedtasks.length === 1">{{ props.row.assignedtasks[0].name }}</q-td>
|
||||
<q-td v-if="props.row.assignedtasks.length > 1"
|
||||
>{{ props.row.assignedtasks.length }} Tasks</q-td
|
||||
>
|
||||
<q-td v-else-if="props.row.assignedtasks.length === 1">{{
|
||||
props.row.assignedtasks[0].name
|
||||
}}</q-td>
|
||||
<q-td v-else></q-td>
|
||||
</q-tr>
|
||||
</template>
|
||||
@@ -194,9 +240,21 @@ export default {
|
||||
{ name: "smsalert", field: "text_alert", align: "left" },
|
||||
{ name: "emailalert", field: "email_alert", align: "left" },
|
||||
{ name: "dashboardalert", field: "dashboard_alert", align: "left" },
|
||||
{ name: "desc", field: "readable_desc", label: "Description", align: "left", sortable: true },
|
||||
{
|
||||
name: "desc",
|
||||
field: "readable_desc",
|
||||
label: "Description",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{ name: "status", label: "Status", field: "status", align: "left" },
|
||||
{ name: "assigned_task", label: "Assigned Tasks", field: "assigned_task", align: "left", sortable: true },
|
||||
{
|
||||
name: "assigned_task",
|
||||
label: "Assigned Tasks",
|
||||
field: "assigned_task",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
],
|
||||
pagination: {
|
||||
rowsPerPage: 0,
|
||||
@@ -215,11 +273,11 @@ export default {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.get(`/automation/policies/${this.selectedPolicy}/checks/`)
|
||||
.then(r => {
|
||||
.then((r) => {
|
||||
this.checks = r.data;
|
||||
this.$q.loading.hide();
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
@@ -240,7 +298,7 @@ export default {
|
||||
const color = !action ? "positive" : "warning";
|
||||
this.$axios
|
||||
.put(`/checks/${id}/`, data)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.$q.loading.hide();
|
||||
this.$q.notify({
|
||||
color: color,
|
||||
@@ -248,7 +306,7 @@ export default {
|
||||
message: `${alert_type} alerts ${act}`,
|
||||
});
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
@@ -263,12 +321,12 @@ export default {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.delete(`/checks/${check.id}/`)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.getChecks();
|
||||
this.$q.loading.hide();
|
||||
this.notifySuccess("Check Deleted!");
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
});
|
||||
@@ -310,4 +368,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@@ -2,7 +2,14 @@
|
||||
<q-dialog ref="dialog" @hide="onHide">
|
||||
<q-card class="q-dialog-plugin" style="width: 90vw; max-width: 90vw">
|
||||
<q-bar>
|
||||
<q-btn @click="getPolicyTree" class="q-mr-sm" dense flat push icon="refresh" />Policy Overview
|
||||
<q-btn
|
||||
@click="getPolicyTree"
|
||||
class="q-mr-sm"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
icon="refresh"
|
||||
/>Policy Overview
|
||||
<q-space />
|
||||
<q-btn dense flat icon="close" v-close-popup>
|
||||
<q-tooltip class="bg-white text-primary">Close</q-tooltip>
|
||||
@@ -36,7 +43,12 @@
|
||||
<q-tab name="checks" icon="fas fa-check-double" label="Checks" />
|
||||
<q-tab name="tasks" icon="fas fa-tasks" label="Tasks" />
|
||||
</q-tabs>
|
||||
<q-tab-panels v-model="selectedTab" animated transition-prev="jump-up" transition-next="jump-up">
|
||||
<q-tab-panels
|
||||
v-model="selectedTab"
|
||||
animated
|
||||
transition-prev="jump-up"
|
||||
transition-next="jump-up"
|
||||
>
|
||||
<q-tab-panel name="checks">
|
||||
<PolicyChecksTab
|
||||
v-if="!!selectedPolicyId"
|
||||
@@ -82,11 +94,11 @@ export default {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.get("/automation/policies/overview/")
|
||||
.then(r => {
|
||||
.then((r) => {
|
||||
this.processTreeDataFromApi(r.data);
|
||||
this.$q.loading.hide();
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
@@ -152,7 +164,8 @@ export default {
|
||||
disabled = " (disabled)";
|
||||
}
|
||||
|
||||
const label = client.workstation_policy.name + " (Workstations)" + disabled;
|
||||
const label =
|
||||
client.workstation_policy.name + " (Workstations)" + disabled;
|
||||
client_temp["children"].push({
|
||||
label: label,
|
||||
icon: "policy",
|
||||
@@ -201,7 +214,8 @@ export default {
|
||||
disabled = " (disabled)";
|
||||
}
|
||||
|
||||
const label = site.workstation_policy.name + " (Workstations)" + disabled;
|
||||
const label =
|
||||
site.workstation_policy.name + " (Workstations)" + disabled;
|
||||
site_temp["children"].push({
|
||||
label: label,
|
||||
icon: "policy",
|
||||
|
@@ -42,16 +42,29 @@
|
||||
filterable
|
||||
/>
|
||||
|
||||
<q-checkbox label="Block policy inheritance" v-model="blockInheritance">
|
||||
<q-tooltip>This {{ type }} will not inherit from higher policies</q-tooltip>
|
||||
<q-checkbox
|
||||
label="Block policy inheritance"
|
||||
v-model="blockInheritance"
|
||||
>
|
||||
<q-tooltip
|
||||
>This {{ type }} will not inherit from higher policies</q-tooltip
|
||||
>
|
||||
</q-checkbox>
|
||||
</q-card-section>
|
||||
<q-card-section v-else>
|
||||
No Automation Policies have been setup. Go to Settings > Automation Manager
|
||||
No Automation Policies have been setup. Go to Settings > Automation
|
||||
Manager
|
||||
</q-card-section>
|
||||
<q-card-actions align="right">
|
||||
<q-btn dense flat label="Cancel" v-close-popup />
|
||||
<q-btn v-if="options.length > 0" dense flat label="Submit" color="primary" type="submit" />
|
||||
<q-btn
|
||||
v-if="options.length > 0"
|
||||
dense
|
||||
flat
|
||||
label="Submit"
|
||||
color="primary"
|
||||
type="submit"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-form>
|
||||
</q-card>
|
||||
@@ -142,12 +155,12 @@ export default {
|
||||
|
||||
this.$axios
|
||||
.put(url, data)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.$q.loading.hide();
|
||||
this.onOk();
|
||||
this.notifySuccess("Policies Updated Successfully!");
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
@@ -155,15 +168,15 @@ export default {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.get("/automation/policies/")
|
||||
.then(r => {
|
||||
this.options = r.data.map(policy => ({
|
||||
.then((r) => {
|
||||
this.options = r.data.map((policy) => ({
|
||||
label: policy.name,
|
||||
value: policy.id,
|
||||
}));
|
||||
|
||||
this.$q.loading.hide();
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
|
@@ -77,12 +77,12 @@ export default {
|
||||
onSubmit() {
|
||||
this.$axios
|
||||
.put(`automation/policies/${this.policy.id}/`, this.localPolicy)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.$q.loading.hide();
|
||||
this.onOk();
|
||||
this.notifySuccess("Policy exclusions added");
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
@@ -90,12 +90,17 @@ export default {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.get("/clients/")
|
||||
.then(r => {
|
||||
this.clientOptions = r.data.map(client => ({ label: client.name, value: client.id }));
|
||||
.then((r) => {
|
||||
this.clientOptions = r.data.map((client) => ({
|
||||
label: client.name,
|
||||
value: client.id,
|
||||
}));
|
||||
|
||||
r.data.forEach(client => {
|
||||
r.data.forEach((client) => {
|
||||
this.siteOptions.push({ category: client.name });
|
||||
client.sites.forEach(site => this.siteOptions.push({ label: site.name, value: site.id }));
|
||||
client.sites.forEach((site) =>
|
||||
this.siteOptions.push({ label: site.name, value: site.id })
|
||||
);
|
||||
});
|
||||
this.$q.loading.hide();
|
||||
})
|
||||
@@ -104,7 +109,9 @@ export default {
|
||||
});
|
||||
},
|
||||
getOptions() {
|
||||
this.getAgentOptions("id").then(options => (this.agentOptions = Object.freeze(options)));
|
||||
this.getAgentOptions("id").then(
|
||||
(options) => (this.agentOptions = Object.freeze(options))
|
||||
);
|
||||
this.getClientsandSites();
|
||||
},
|
||||
show() {
|
||||
|
@@ -18,7 +18,12 @@
|
||||
<q-card-section class="row">
|
||||
<div class="col-2">Name:</div>
|
||||
<div class="col-10">
|
||||
<q-input outlined dense v-model="localPolicy.name" :rules="[val => !!val || '*Required']" />
|
||||
<q-input
|
||||
outlined
|
||||
dense
|
||||
v-model="localPolicy.name"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
<q-card-section class="row">
|
||||
@@ -85,12 +90,12 @@ export default {
|
||||
if (this.editing) {
|
||||
this.$axios
|
||||
.put(`/automation/policies/${data.id}/`, data)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.$q.loading.hide();
|
||||
this.onOk();
|
||||
this.notifySuccess("Policy edited!");
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
} else {
|
||||
@@ -100,12 +105,14 @@ export default {
|
||||
|
||||
this.$axios
|
||||
.post("/automation/policies/", data)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.$q.loading.hide();
|
||||
this.onOk();
|
||||
this.notifySuccess("Policy added. Now you can add Tasks and Checks!");
|
||||
this.notifySuccess(
|
||||
"Policy added. Now you can add Tasks and Checks!"
|
||||
);
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
}
|
||||
|
@@ -11,7 +11,10 @@
|
||||
<q-card-section>
|
||||
<q-table
|
||||
style="max-height: 35vh"
|
||||
:table-class="{ 'table-bgcolor': !$q.dark.isActive, 'table-bgcolor-dark': $q.dark.isActive }"
|
||||
:table-class="{
|
||||
'table-bgcolor': !$q.dark.isActive,
|
||||
'table-bgcolor-dark': $q.dark.isActive,
|
||||
}"
|
||||
class="tabs-tbl-sticky"
|
||||
:rows="data"
|
||||
:columns="columns"
|
||||
@@ -36,12 +39,21 @@
|
||||
<q-td>{{ props.row.hostname }}</q-td>
|
||||
<!-- status icon -->
|
||||
<q-td v-if="props.row.status === 'passing'">
|
||||
<q-icon style="font-size: 1.3rem" color="positive" name="check_circle">
|
||||
<q-icon
|
||||
style="font-size: 1.3rem"
|
||||
color="positive"
|
||||
name="check_circle"
|
||||
>
|
||||
<q-tooltip>Passing</q-tooltip>
|
||||
</q-icon>
|
||||
</q-td>
|
||||
<q-td v-else-if="props.row.status === 'failing'">
|
||||
<q-icon v-if="props.row.alert_severity === 'info'" style="font-size: 1.3rem" color="info" name="info">
|
||||
<q-icon
|
||||
v-if="props.row.alert_severity === 'info'"
|
||||
style="font-size: 1.3rem"
|
||||
color="info"
|
||||
name="info"
|
||||
>
|
||||
<q-tooltip>Informational</q-tooltip>
|
||||
</q-icon>
|
||||
<q-icon
|
||||
@@ -52,17 +64,32 @@
|
||||
>
|
||||
<q-tooltip>Warning</q-tooltip>
|
||||
</q-icon>
|
||||
<q-icon v-else style="font-size: 1.3rem" color="negative" name="error">
|
||||
<q-icon
|
||||
v-else
|
||||
style="font-size: 1.3rem"
|
||||
color="negative"
|
||||
name="error"
|
||||
>
|
||||
<q-tooltip>Error</q-tooltip>
|
||||
</q-icon>
|
||||
</q-td>
|
||||
<q-td v-else></q-td>
|
||||
<!-- status text -->
|
||||
<q-td v-if="props.row.status === 'pending'">Awaiting First Synchronization</q-td>
|
||||
<q-td v-else-if="props.row.sync_status === 'notsynced'">Will sync on next agent checkin</q-td>
|
||||
<q-td v-else-if="props.row.sync_status === 'synced'">Synced with agent</q-td>
|
||||
<q-td v-else-if="props.row.sync_status === 'pendingdeletion'">Pending deletion on agent</q-td>
|
||||
<q-td v-else-if="props.row.sync_status === 'initial'">Waiting for task creation on agent</q-td>
|
||||
<q-td v-if="props.row.status === 'pending'"
|
||||
>Awaiting First Synchronization</q-td
|
||||
>
|
||||
<q-td v-else-if="props.row.sync_status === 'notsynced'"
|
||||
>Will sync on next agent checkin</q-td
|
||||
>
|
||||
<q-td v-else-if="props.row.sync_status === 'synced'"
|
||||
>Synced with agent</q-td
|
||||
>
|
||||
<q-td v-else-if="props.row.sync_status === 'pendingdeletion'"
|
||||
>Pending deletion on agent</q-td
|
||||
>
|
||||
<q-td v-else-if="props.row.sync_status === 'initial'"
|
||||
>Waiting for task creation on agent</q-td
|
||||
>
|
||||
<q-td v-else></q-td>
|
||||
<!-- more info -->
|
||||
<q-td v-if="props.row.check_type === 'ping'">
|
||||
@@ -75,7 +102,10 @@
|
||||
</q-td>
|
||||
<q-td
|
||||
v-else-if="
|
||||
props.row.check_type === 'script' || props.row.retcode || props.row.stdout || props.row.stderr
|
||||
props.row.check_type === 'script' ||
|
||||
props.row.retcode ||
|
||||
props.row.stdout ||
|
||||
props.row.stderr
|
||||
"
|
||||
>
|
||||
<span
|
||||
@@ -93,13 +123,21 @@
|
||||
>output</span
|
||||
>
|
||||
</q-td>
|
||||
<q-td v-else-if="props.row.check_type === 'cpuload' || props.row.check_type === 'memory'">{{
|
||||
props.row.history_info
|
||||
<q-td
|
||||
v-else-if="
|
||||
props.row.check_type === 'cpuload' ||
|
||||
props.row.check_type === 'memory'
|
||||
"
|
||||
>{{ props.row.history_info }}</q-td
|
||||
>
|
||||
<q-td v-else-if="props.row.more_info">{{
|
||||
props.row.more_info
|
||||
}}</q-td>
|
||||
<q-td v-else-if="props.row.more_info">{{ props.row.more_info }}</q-td>
|
||||
<q-td v-else>Awaiting Output</q-td>
|
||||
<!-- last run -->
|
||||
<q-td>{{ props.row.last_run ? formatDate(props.row.last_run) : "Never" }}</q-td>
|
||||
<q-td>{{
|
||||
props.row.last_run ? formatDate(props.row.last_run) : "Never"
|
||||
}}</q-td>
|
||||
</q-tr>
|
||||
</template>
|
||||
</q-table>
|
||||
@@ -131,7 +169,7 @@ export default {
|
||||
},
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
setup() {
|
||||
// setup vuex store
|
||||
const store = useStore();
|
||||
const formatDate = computed(() => store.getters.formatDate);
|
||||
@@ -144,9 +182,21 @@ export default {
|
||||
return {
|
||||
data: [],
|
||||
columns: [
|
||||
{ name: "agent", label: "Hostname", field: "agent", align: "left", sortable: true },
|
||||
{
|
||||
name: "agent",
|
||||
label: "Hostname",
|
||||
field: "agent",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{ name: "statusicon", align: "left" },
|
||||
{ name: "status", label: "Status", field: "status", align: "left", sortable: true },
|
||||
{
|
||||
name: "status",
|
||||
label: "Status",
|
||||
field: "status",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "moreinfo",
|
||||
label: "More Info",
|
||||
@@ -171,7 +221,9 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
title() {
|
||||
return !!this.item.readable_desc ? this.item.readable_desc + " Status" : this.item.name + " Status";
|
||||
return !!this.item.readable_desc
|
||||
? this.item.readable_desc + " Status"
|
||||
: this.item.name + " Status";
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
@@ -179,11 +231,11 @@ export default {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.get(`/automation/checks/${this.item.id}/status/`)
|
||||
.then(r => {
|
||||
.then((r) => {
|
||||
this.$q.loading.hide();
|
||||
this.data = r.data;
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
@@ -191,11 +243,11 @@ export default {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.get(`/automation/tasks/${this.item.id}/status/`)
|
||||
.then(r => {
|
||||
.then((r) => {
|
||||
this.$q.loading.hide();
|
||||
this.data = r.data;
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
|
@@ -10,13 +10,17 @@
|
||||
</q-bar>
|
||||
<q-card-section
|
||||
class="row items-center"
|
||||
v-if="related.default_server_policy || related.default_workstation_policy"
|
||||
v-if="
|
||||
related.default_server_policy || related.default_workstation_policy
|
||||
"
|
||||
>
|
||||
<div v-if="related.default_server_policy" class="text-body">
|
||||
<q-icon name="error_outline" color="info" size="1.5em" />This policy is set as the Default Server Policy.
|
||||
<q-icon name="error_outline" color="info" size="1.5em" />This policy
|
||||
is set as the Default Server Policy.
|
||||
</div>
|
||||
<div v-if="related.default_workstation_policy" class="text-body">
|
||||
<q-icon name="error_outline" color="info" size="1.5em" />This policy is set as the Default Workstation Policy.
|
||||
<q-icon name="error_outline" color="info" size="1.5em" />This policy
|
||||
is set as the Default Workstation Policy.
|
||||
</div>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
@@ -41,7 +45,10 @@
|
||||
<q-tab-panels v-model="tab" :animated="false">
|
||||
<q-tab-panel name="clients">
|
||||
<q-list separator padding>
|
||||
<q-item v-for="item in related.server_clients" :key="item.id + 'servers'">
|
||||
<q-item
|
||||
v-for="item in related.server_clients"
|
||||
:key="item.id + 'servers'"
|
||||
>
|
||||
<q-item-section>
|
||||
<q-item-label>{{ item.name }}</q-item-label>
|
||||
</q-item-section>
|
||||
@@ -51,7 +58,10 @@
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item v-for="item in related.workstation_clients" :key="item.id + 'workstations'">
|
||||
<q-item
|
||||
v-for="item in related.workstation_clients"
|
||||
:key="item.id + 'workstations'"
|
||||
>
|
||||
<q-item-section>
|
||||
<q-item-label>{{ item.name }}</q-item-label>
|
||||
</q-item-section>
|
||||
@@ -66,7 +76,10 @@
|
||||
|
||||
<q-tab-panel name="sites">
|
||||
<q-list separator padding>
|
||||
<q-item v-for="item in related.server_sites" :key="item.id + 'servers'">
|
||||
<q-item
|
||||
v-for="item in related.server_sites"
|
||||
:key="item.id + 'servers'"
|
||||
>
|
||||
<q-item-section>
|
||||
<q-item-label>{{ item.name }}</q-item-label>
|
||||
<q-item-label caption>{{ item.client_name }}</q-item-label>
|
||||
@@ -77,7 +90,10 @@
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item v-for="item in related.workstation_sites" :key="item.id + 'workstations'">
|
||||
<q-item
|
||||
v-for="item in related.workstation_sites"
|
||||
:key="item.id + 'workstations'"
|
||||
>
|
||||
<q-item-section>
|
||||
<q-item-label>{{ item.name }}</q-item-label>
|
||||
<q-item-label caption>{{ item.client_name }}</q-item-label>
|
||||
@@ -150,11 +166,11 @@ export default {
|
||||
|
||||
this.$axios
|
||||
.get(`/automation/policies/${this.policy.id}/related/`)
|
||||
.then(r => {
|
||||
.then((r) => {
|
||||
this.$q.loading.hide();
|
||||
this.related = r.data;
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
|
@@ -17,7 +17,10 @@
|
||||
type="number"
|
||||
v-model.number="state.warning_threshold"
|
||||
label="Warning Threshold (%)"
|
||||
:rules="[val => val >= 0 || 'Minimum threshold is 0', val => val < 100 || 'Maximum threshold is 99']"
|
||||
:rules="[
|
||||
(val) => val >= 0 || 'Minimum threshold is 0',
|
||||
(val) => val < 100 || 'Maximum threshold is 99',
|
||||
]"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
@@ -27,7 +30,10 @@
|
||||
type="number"
|
||||
v-model.number="state.error_threshold"
|
||||
label="Error Threshold (%)"
|
||||
:rules="[val => val >= 0 || 'Minimum threshold is 0', val => val < 100 || 'Maximum threshold is 99']"
|
||||
:rules="[
|
||||
(val) => val >= 0 || 'Minimum threshold is 0',
|
||||
(val) => val < 100 || 'Maximum threshold is 99',
|
||||
]"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
@@ -53,7 +59,14 @@
|
||||
</div>
|
||||
<q-card-actions align="right">
|
||||
<q-btn dense flat label="Cancel" v-close-popup />
|
||||
<q-btn :loading="loading" dense flat label="Save" color="primary" type="submit" />
|
||||
<q-btn
|
||||
:loading="loading"
|
||||
dense
|
||||
flat
|
||||
label="Save"
|
||||
color="primary"
|
||||
type="submit"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-form>
|
||||
</q-card>
|
||||
|
@@ -19,7 +19,7 @@
|
||||
v-model="state.disk"
|
||||
:options="diskOptions"
|
||||
label="Disk"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
@@ -29,7 +29,10 @@
|
||||
type="number"
|
||||
v-model.number="state.warning_threshold"
|
||||
label="Warning Threshold Remaining (%)"
|
||||
:rules="[val => val >= 0 || 'Minimum threshold is 0', val => val < 100 || 'Maximum threshold is 99']"
|
||||
:rules="[
|
||||
(val) => val >= 0 || 'Minimum threshold is 0',
|
||||
(val) => val < 100 || 'Maximum threshold is 99',
|
||||
]"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
@@ -39,7 +42,10 @@
|
||||
type="number"
|
||||
v-model.number="state.error_threshold"
|
||||
label="Error Threshold Remaining (%)"
|
||||
:rules="[val => val >= 0 || 'Minimum threshold is 0', val => val < 100 || 'Maximum threshold is 99']"
|
||||
:rules="[
|
||||
(val) => val >= 0 || 'Minimum threshold is 0',
|
||||
(val) => val < 100 || 'Maximum threshold is 99',
|
||||
]"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
@@ -65,7 +71,14 @@
|
||||
</div>
|
||||
<q-card-actions align="right">
|
||||
<q-btn dense flat label="Cancel" v-close-popup />
|
||||
<q-btn :loading="loading" dense flat label="Save" color="primary" type="submit" />
|
||||
<q-btn
|
||||
:loading="loading"
|
||||
dense
|
||||
flat
|
||||
label="Save"
|
||||
color="primary"
|
||||
type="submit"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-form>
|
||||
</q-card>
|
||||
|
@@ -17,7 +17,7 @@
|
||||
outlined
|
||||
v-model="state.name"
|
||||
label="Descriptive Name"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
@@ -48,16 +48,29 @@
|
||||
outlined
|
||||
v-model="state.event_id"
|
||||
label="Event ID (Use * to match every event ID)"
|
||||
:rules="[val => validateEventID(val) || 'Invalid Event ID']"
|
||||
:rules="[(val) => validateEventID(val) || 'Invalid Event ID']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<q-checkbox v-model="eventSource" label="Event source" />
|
||||
<q-input dense outlined v-model="state.event_source" :disable="!eventSource" />
|
||||
<q-input
|
||||
dense
|
||||
outlined
|
||||
v-model="state.event_source"
|
||||
:disable="!eventSource"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<q-checkbox v-model="eventMessage" label="Message contains string" />
|
||||
<q-input dense outlined v-model="state.event_message" :disable="!eventMessage" />
|
||||
<q-checkbox
|
||||
v-model="eventMessage"
|
||||
label="Message contains string"
|
||||
/>
|
||||
<q-input
|
||||
dense
|
||||
outlined
|
||||
v-model="state.event_message"
|
||||
:disable="!eventMessage"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<q-input
|
||||
@@ -66,20 +79,45 @@
|
||||
v-model.number="state.search_last_days"
|
||||
label="How many previous days to search (Enter 0 for the entire log)"
|
||||
:rules="[
|
||||
val => !!val.toString() || '*Required',
|
||||
val => val >= 0 || 'Min 0',
|
||||
val => val <= 9999 || 'Max 9999',
|
||||
(val) => !!val.toString() || '*Required',
|
||||
(val) => val >= 0 || 'Min 0',
|
||||
(val) => val <= 9999 || 'Max 9999',
|
||||
]"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<span>Event Type:</span>
|
||||
<div class="q-gutter-sm">
|
||||
<q-radio dense v-model="state.event_type" val="INFO" label="Information" />
|
||||
<q-radio dense v-model="state.event_type" val="WARNING" label="Warning" />
|
||||
<q-radio dense v-model="state.event_type" val="ERROR" label="Error" />
|
||||
<q-radio dense v-model="state.event_type" val="AUDIT_SUCCESS" label="Success Audit" />
|
||||
<q-radio dense v-model="state.event_type" val="AUDIT_FAILURE" label="Failure Audit" />
|
||||
<q-radio
|
||||
dense
|
||||
v-model="state.event_type"
|
||||
val="INFO"
|
||||
label="Information"
|
||||
/>
|
||||
<q-radio
|
||||
dense
|
||||
v-model="state.event_type"
|
||||
val="WARNING"
|
||||
label="Warning"
|
||||
/>
|
||||
<q-radio
|
||||
dense
|
||||
v-model="state.event_type"
|
||||
val="ERROR"
|
||||
label="Error"
|
||||
/>
|
||||
<q-radio
|
||||
dense
|
||||
v-model="state.event_type"
|
||||
val="AUDIT_SUCCESS"
|
||||
label="Success Audit"
|
||||
/>
|
||||
<q-radio
|
||||
dense
|
||||
v-model="state.event_type"
|
||||
val="AUDIT_FAILURE"
|
||||
label="Failure Audit"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
@@ -126,7 +164,14 @@
|
||||
</div>
|
||||
<q-card-actions align="right">
|
||||
<q-btn dense flat label="Cancel" v-close-popup />
|
||||
<q-btn :loading="loading" dense flat label="Save" color="primary" type="submit" />
|
||||
<q-btn
|
||||
:loading="loading"
|
||||
dense
|
||||
flat
|
||||
label="Save"
|
||||
color="primary"
|
||||
type="submit"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-form>
|
||||
</q-card>
|
||||
@@ -152,7 +197,15 @@ export default {
|
||||
const { dialogRef, onDialogHide, onDialogOK } = useDialogPluginComponent();
|
||||
|
||||
// check logic
|
||||
const { state, loading, submit, failOptions, logNameOptions, failWhenOptions, severityOptions } = useCheckModal({
|
||||
const {
|
||||
state,
|
||||
loading,
|
||||
submit,
|
||||
failOptions,
|
||||
logNameOptions,
|
||||
failWhenOptions,
|
||||
severityOptions,
|
||||
} = useCheckModal({
|
||||
editCheck: props.check,
|
||||
initialState: {
|
||||
...props.parent,
|
||||
@@ -188,17 +241,18 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
watch(eventMessage, (newValue, oldValue) => {
|
||||
watch(eventMessage, () => {
|
||||
state.value.event_message = null;
|
||||
});
|
||||
|
||||
watch(eventSource, (newValue, oldValue) => {
|
||||
watch(eventSource, () => {
|
||||
state.value.event_source = null;
|
||||
});
|
||||
|
||||
function beforeSubmit() {
|
||||
// format check data for saving
|
||||
state.value.event_id_is_wildcard = state.value.event_id === "*" ? true : false;
|
||||
state.value.event_id_is_wildcard =
|
||||
state.value.event_id === "*" ? true : false;
|
||||
if (state.value.event_source === "") state.value.event_source = null;
|
||||
if (state.value.event_message === "") state.value.event_message = null;
|
||||
|
||||
|
@@ -12,7 +12,10 @@
|
||||
<q-table
|
||||
dense
|
||||
style="height: 65vh"
|
||||
:table-class="{ 'table-bgcolor': !$q.dark.isActive, 'table-bgcolor-dark': $q.dark.isActive }"
|
||||
:table-class="{
|
||||
'table-bgcolor': !$q.dark.isActive,
|
||||
'table-bgcolor-dark': $q.dark.isActive,
|
||||
}"
|
||||
class="tabs-tbl-sticky"
|
||||
:filter="filter"
|
||||
:rows="evtLogData.check_result.extra_details.log"
|
||||
@@ -26,12 +29,22 @@
|
||||
>
|
||||
<template v-slot:top>
|
||||
<q-space />
|
||||
<q-input v-model="filter" outlined label="Search" dense clearable class="q-pr-sm">
|
||||
<q-input
|
||||
v-model="filter"
|
||||
outlined
|
||||
label="Search"
|
||||
dense
|
||||
clearable
|
||||
class="q-pr-sm"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<q-icon name="search" color="primary" />
|
||||
</template>
|
||||
</q-input>
|
||||
<export-table-btn :data="evtLogData.check_result.extra_details.log" :columns="columns" />
|
||||
<export-table-btn
|
||||
:data="evtLogData.check_result.extra_details.log"
|
||||
:columns="columns"
|
||||
/>
|
||||
</template>
|
||||
</q-table>
|
||||
</div>
|
||||
@@ -50,23 +63,51 @@ import ExportTableBtn from "@/components/ui/ExportTableBtn";
|
||||
|
||||
// static data
|
||||
const columns = [
|
||||
{ name: "eventType", label: "Type", field: "eventType", align: "left", sortable: true },
|
||||
{ name: "source", label: "Source", field: "source", align: "left", sortable: true },
|
||||
{ name: "eventID", label: "Event ID", field: "eventID", align: "left", sortable: true },
|
||||
{
|
||||
name: "eventType",
|
||||
label: "Type",
|
||||
field: "eventType",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "source",
|
||||
label: "Source",
|
||||
field: "source",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "eventID",
|
||||
label: "Event ID",
|
||||
field: "eventID",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{ name: "time", label: "Time", field: "time", align: "left", sortable: true },
|
||||
{ name: "message", label: "Message", field: "message", align: "left", sortable: true },
|
||||
{
|
||||
name: "message",
|
||||
label: "Message",
|
||||
field: "message",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
];
|
||||
export default {
|
||||
name: "EventLogCheckOutput",
|
||||
components: { ExportTableBtn },
|
||||
emits: [...useDialogPluginComponent.emits],
|
||||
props: { evtLogData: !Object },
|
||||
setup(props) {
|
||||
setup() {
|
||||
// setup quasar
|
||||
const { dialogRef, onDialogHide } = useDialogPluginComponent();
|
||||
|
||||
const filter = ref("");
|
||||
const pagination = ref({ rowsPerPage: 0, sortBy: "time", descending: true });
|
||||
const pagination = ref({
|
||||
rowsPerPage: 0,
|
||||
sortBy: "time",
|
||||
descending: true,
|
||||
});
|
||||
|
||||
return {
|
||||
// reactive data
|
||||
|
@@ -17,7 +17,10 @@
|
||||
type="number"
|
||||
v-model.number="state.warning_threshold"
|
||||
label="Warning Threshold (%)"
|
||||
:rules="[val => val >= 0 || 'Minimum threshold is 0', val => val < 100 || 'Maximum threshold is 99']"
|
||||
:rules="[
|
||||
(val) => val >= 0 || 'Minimum threshold is 0',
|
||||
(val) => val < 100 || 'Maximum threshold is 99',
|
||||
]"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
@@ -27,7 +30,10 @@
|
||||
type="number"
|
||||
v-model.number="state.error_threshold"
|
||||
label="Error Threshold (%)"
|
||||
:rules="[val => val >= 0 || 'Minimum threshold is 0', val => val < 100 || 'Maximum threshold is 99']"
|
||||
:rules="[
|
||||
(val) => val >= 0 || 'Minimum threshold is 0',
|
||||
(val) => val < 100 || 'Maximum threshold is 99',
|
||||
]"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
@@ -53,7 +59,14 @@
|
||||
</div>
|
||||
<q-card-actions align="right">
|
||||
<q-btn dense flat label="Cancel" v-close-popup />
|
||||
<q-btn :loading="loading" dense flat label="Save" color="primary" type="submit" />
|
||||
<q-btn
|
||||
:loading="loading"
|
||||
dense
|
||||
flat
|
||||
label="Save"
|
||||
color="primary"
|
||||
type="submit"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-form>
|
||||
</q-card>
|
||||
|
@@ -17,11 +17,17 @@
|
||||
dense
|
||||
v-model="state.name"
|
||||
label="Descriptive Name"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<q-input dense outlined v-model="state.ip" label="Hostname or IP" :rules="[val => !!val || '*Required']" />
|
||||
<q-input
|
||||
dense
|
||||
outlined
|
||||
v-model="state.ip"
|
||||
label="Hostname or IP"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<q-select
|
||||
@@ -60,7 +66,14 @@
|
||||
</div>
|
||||
<q-card-actions align="right">
|
||||
<q-btn dense flat label="Cancel" v-close-popup />
|
||||
<q-btn :loading="loading" dense flat label="Save" color="primary" type="submit" />
|
||||
<q-btn
|
||||
:loading="loading"
|
||||
dense
|
||||
flat
|
||||
label="Save"
|
||||
color="primary"
|
||||
type="submit"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-form>
|
||||
</q-card>
|
||||
@@ -84,7 +97,8 @@ export default {
|
||||
const { dialogRef, onDialogHide, onDialogOK } = useDialogPluginComponent();
|
||||
|
||||
// check logic
|
||||
const { state, loading, submit, failOptions, severityOptions } = useCheckModal({
|
||||
const { state, loading, submit, failOptions, severityOptions } =
|
||||
useCheckModal({
|
||||
editCheck: props.check,
|
||||
initialState: {
|
||||
...props.parent,
|
||||
@@ -115,23 +129,5 @@ export default {
|
||||
onDialogOK,
|
||||
};
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pingcheck: {
|
||||
check_type: "ping",
|
||||
name: null,
|
||||
ip: null,
|
||||
alert_severity: "warning",
|
||||
fails_b4_alert: 1,
|
||||
run_interval: 0,
|
||||
},
|
||||
severityOptions: [
|
||||
{ label: "Informational", value: "info" },
|
||||
{ label: "Warning", value: "warning" },
|
||||
{ label: "Error", value: "error" },
|
||||
],
|
||||
failOptions: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
@@ -16,7 +16,7 @@
|
||||
<q-form v-else @submit.prevent="submit(onDialogOK)">
|
||||
<q-card-section>
|
||||
<tactical-dropdown
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
outlined
|
||||
v-model="state.script"
|
||||
:options="scriptOptions"
|
||||
@@ -66,7 +66,12 @@
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<q-input outlined dense v-model.number="state.timeout" label="Script Timeout (seconds)" />
|
||||
<q-input
|
||||
outlined
|
||||
dense
|
||||
v-model.number="state.timeout"
|
||||
label="Script Timeout (seconds)"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<q-select
|
||||
@@ -90,7 +95,14 @@
|
||||
</q-card-section>
|
||||
<q-card-actions align="right">
|
||||
<q-btn dense flat label="Cancel" v-close-popup />
|
||||
<q-btn :loading="loading" dense flat label="Save" color="primary" type="submit" />
|
||||
<q-btn
|
||||
:loading="loading"
|
||||
dense
|
||||
flat
|
||||
label="Save"
|
||||
color="primary"
|
||||
type="submit"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-form>
|
||||
</q-card>
|
||||
@@ -120,13 +132,14 @@ export default {
|
||||
const { dialogRef, onDialogHide, onDialogOK } = useDialogPluginComponent();
|
||||
|
||||
// setup script dropdown
|
||||
const { script, scriptOptions, defaultTimeout, defaultArgs } = useScriptDropdown(
|
||||
props.check ? props.check.script : undefined,
|
||||
{ onMount: true }
|
||||
);
|
||||
const { script, scriptOptions, defaultTimeout, defaultArgs } =
|
||||
useScriptDropdown(props.check ? props.check.script : undefined, {
|
||||
onMount: true,
|
||||
});
|
||||
|
||||
// check logic
|
||||
const { state, loading, submit, failOptions, severityOptions } = useCheckModal({
|
||||
const { state, loading, submit, failOptions, severityOptions } =
|
||||
useCheckModal({
|
||||
editCheck: props.check,
|
||||
initialState: {
|
||||
...props.parent,
|
||||
|
@@ -47,7 +47,7 @@ export default {
|
||||
name: "ScriptOutput",
|
||||
emits: [...useDialogPluginComponent.emits],
|
||||
props: { scriptInfo: !Object },
|
||||
setup(props) {
|
||||
setup() {
|
||||
// setup vuex
|
||||
const store = useStore();
|
||||
const formatDate = computed(() => store.getters.formatDate);
|
||||
|
@@ -19,10 +19,15 @@
|
||||
val="default"
|
||||
label="Choose from defaults"
|
||||
/>
|
||||
<q-radio v-if="isPolicy && !check" v-model="state.svc_policy_mode" val="manual" label="Enter manually" />
|
||||
<q-radio
|
||||
v-if="isPolicy && !check"
|
||||
v-model="state.svc_policy_mode"
|
||||
val="manual"
|
||||
label="Enter manually"
|
||||
/>
|
||||
<q-select
|
||||
v-if="isPolicy && state.svc_policy_mode === 'default' && !check"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
dense
|
||||
options-dense
|
||||
outlined
|
||||
@@ -35,7 +40,7 @@
|
||||
/>
|
||||
<q-input
|
||||
v-if="isPolicy && state.svc_policy_mode === 'manual'"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
outlined
|
||||
dense
|
||||
v-model="state.svc_name"
|
||||
@@ -43,7 +48,7 @@
|
||||
/>
|
||||
<q-input
|
||||
v-if="isPolicy && state.svc_policy_mode === 'manual'"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
outlined
|
||||
dense
|
||||
v-model="state.svc_display_name"
|
||||
@@ -53,7 +58,7 @@
|
||||
<!-- disable selection if editing -->
|
||||
<q-select
|
||||
v-if="isAgent"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
dense
|
||||
options-dense
|
||||
outlined
|
||||
@@ -66,11 +71,20 @@
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<q-checkbox v-model="state.pass_if_start_pending" label="PASS if service is in 'Start Pending' mode" />
|
||||
<q-checkbox
|
||||
v-model="state.pass_if_start_pending"
|
||||
label="PASS if service is in 'Start Pending' mode"
|
||||
/>
|
||||
<br />
|
||||
<q-checkbox v-model="state.pass_if_svc_not_exist" label="PASS if service doesn't exist" />
|
||||
<q-checkbox
|
||||
v-model="state.pass_if_svc_not_exist"
|
||||
label="PASS if service doesn't exist"
|
||||
/>
|
||||
<br />
|
||||
<q-checkbox v-model="state.restart_if_stopped" label="Restart service if it's stopped" />
|
||||
<q-checkbox
|
||||
v-model="state.restart_if_stopped"
|
||||
label="Restart service if it's stopped"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<q-select
|
||||
@@ -107,7 +121,14 @@
|
||||
</div>
|
||||
<q-card-actions align="right">
|
||||
<q-btn dense flat label="Cancel" v-close-popup />
|
||||
<q-btn :loading="loading" dense flat label="Save" color="primary" type="submit" />
|
||||
<q-btn
|
||||
:loading="loading"
|
||||
dense
|
||||
flat
|
||||
label="Save"
|
||||
color="primary"
|
||||
type="submit"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-form>
|
||||
</q-card>
|
||||
@@ -132,7 +153,14 @@ export default {
|
||||
const { dialogRef, onDialogHide, onDialogOK } = useDialogPluginComponent();
|
||||
|
||||
// check logic
|
||||
const { state, loading, submit, failOptions, severityOptions, serviceOptions } = useCheckModal({
|
||||
const {
|
||||
state,
|
||||
loading,
|
||||
submit,
|
||||
failOptions,
|
||||
severityOptions,
|
||||
serviceOptions,
|
||||
} = useCheckModal({
|
||||
editCheck: props.check,
|
||||
initialState: {
|
||||
...props.parent,
|
||||
@@ -151,17 +179,19 @@ export default {
|
||||
|
||||
watch(
|
||||
() => state.value.svc_name,
|
||||
(newvalue, oldValue) => {
|
||||
() => {
|
||||
// prevent error when in manual mode
|
||||
try {
|
||||
state.value.svc_display_name = serviceOptions.value.find(i => i.value === state.value.svc_name).label;
|
||||
state.value.svc_display_name = serviceOptions.value.find(
|
||||
(i) => i.value === state.value.svc_name
|
||||
).label;
|
||||
} catch {}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => state.value.svc_policy_mode,
|
||||
(newValue, oldValue) => {
|
||||
() => {
|
||||
state.value.svc_name = null;
|
||||
state.value.svc_display_name = null;
|
||||
}
|
||||
|
@@ -15,12 +15,12 @@
|
||||
dense
|
||||
v-model="state.name"
|
||||
label="Name"
|
||||
:rules="[val => (val && val.length > 0) || '*Required']"
|
||||
:rules="[(val) => (val && val.length > 0) || '*Required']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section v-if="!client">
|
||||
<q-input
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
outlined
|
||||
dense
|
||||
v-model="site.name"
|
||||
@@ -28,13 +28,23 @@
|
||||
/>
|
||||
</q-card-section>
|
||||
|
||||
<div class="q-pl-sm text-h6" v-if="customFields.length > 0">Custom Fields</div>
|
||||
<div class="q-pl-sm text-h6" v-if="customFields.length > 0">
|
||||
Custom Fields
|
||||
</div>
|
||||
<q-card-section v-for="field in customFields" :key="field.id">
|
||||
<CustomField v-model="custom_fields[field.name]" :field="field" />
|
||||
</q-card-section>
|
||||
<q-card-actions align="right">
|
||||
<q-btn dense flat label="Cancel" v-close-popup />
|
||||
<q-btn :loading="loading" dense flat push label="Save" color="primary" type="submit" />
|
||||
<q-btn
|
||||
:loading="loading"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
label="Save"
|
||||
color="primary"
|
||||
type="submit"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-form>
|
||||
</q-card>
|
||||
@@ -67,7 +77,9 @@ export default {
|
||||
const { dialogRef, onDialogOK, onDialogHide } = useDialogPluginComponent();
|
||||
|
||||
// clients form logic
|
||||
const state = !!props.client ? ref(Object.assign({}, props.client)) : ref({ name: "" });
|
||||
const state = !!props.client
|
||||
? ref(Object.assign({}, props.client))
|
||||
: ref({ name: "" });
|
||||
const site = ref({ name: "" });
|
||||
const custom_fields = ref({});
|
||||
const customFields = ref([]);
|
||||
@@ -78,10 +90,15 @@ export default {
|
||||
const data = {
|
||||
client: state.value,
|
||||
site: site.value,
|
||||
custom_fields: formatCustomFields(customFields.value, custom_fields.value),
|
||||
custom_fields: formatCustomFields(
|
||||
customFields.value,
|
||||
custom_fields.value
|
||||
),
|
||||
};
|
||||
try {
|
||||
const result = !!props.client ? await editClient(props.client.id, data) : await saveClient(data);
|
||||
const result = !!props.client
|
||||
? await editClient(props.client.id, data)
|
||||
: await saveClient(data);
|
||||
notifySuccess(result);
|
||||
onDialogOK();
|
||||
} catch (e) {
|
||||
@@ -95,7 +112,9 @@ export default {
|
||||
const data = await fetchClient(props.client.id);
|
||||
|
||||
for (let field of customFields.value) {
|
||||
const value = data.custom_fields.find(value => value.field === field.id);
|
||||
const value = data.custom_fields.find(
|
||||
(value) => value.field === field.id
|
||||
);
|
||||
|
||||
if (field.type === "multiple") {
|
||||
if (value) custom_fields.value[field.name] = value.value;
|
||||
@@ -113,7 +132,7 @@ export default {
|
||||
|
||||
onMounted(async () => {
|
||||
const fields = await fetchCustomFields({ model: "client" });
|
||||
customFields.value = fields.filter(field => !field.hide_in_ui);
|
||||
customFields.value = fields.filter((field) => !field.hide_in_ui);
|
||||
if (props.client) getClientCustomFieldValues();
|
||||
});
|
||||
|
||||
|
@@ -2,7 +2,14 @@
|
||||
<q-dialog ref="dialogRef" @hide="onDialogHide">
|
||||
<q-card class="q-dialog-plugin" style="width: 70vw">
|
||||
<q-bar>
|
||||
<q-btn @click="getClients" class="q-mr-sm" dense flat push icon="refresh" />Clients Manager
|
||||
<q-btn
|
||||
@click="getClients"
|
||||
class="q-mr-sm"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
icon="refresh"
|
||||
/>Clients Manager
|
||||
<q-space />
|
||||
<q-btn dense flat icon="close" v-close-popup>
|
||||
<q-tooltip class="bg-white text-primary">Close</q-tooltip>
|
||||
@@ -11,7 +18,10 @@
|
||||
<q-table
|
||||
:rows="clients"
|
||||
:columns="columns"
|
||||
:table-class="{ 'table-bgcolor': !$q.dark.isActive, 'table-bgcolor-dark': $q.dark.isActive }"
|
||||
:table-class="{
|
||||
'table-bgcolor': !$q.dark.isActive,
|
||||
'table-bgcolor-dark': $q.dark.isActive,
|
||||
}"
|
||||
class="settings-tbl-sticky"
|
||||
style="height: 70vh"
|
||||
:pagination="{ rowsPerPage: 0, sortBy: 'name', descending: false }"
|
||||
@@ -25,7 +35,15 @@
|
||||
>
|
||||
<!-- top slot -->
|
||||
<template v-slot:top>
|
||||
<q-btn label="New" dense flat push no-caps icon="add" @click="showAddClient" />
|
||||
<q-btn
|
||||
label="New"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
no-caps
|
||||
icon="add"
|
||||
@click="showAddClient"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<!-- loading slot -->
|
||||
@@ -35,17 +53,29 @@
|
||||
|
||||
<!-- body slots -->
|
||||
<template v-slot:body="props">
|
||||
<q-tr :props="props" class="cursor-pointer" @dblclick="showEditClient(props.row)">
|
||||
<q-tr
|
||||
:props="props"
|
||||
class="cursor-pointer"
|
||||
@dblclick="showEditClient(props.row)"
|
||||
>
|
||||
<!-- context menu -->
|
||||
<q-menu context-menu>
|
||||
<q-list dense style="min-width: 200px">
|
||||
<q-item clickable v-close-popup @click="showEditClient(props.row)">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showEditClient(props.row)"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="edit" />
|
||||
</q-item-section>
|
||||
<q-item-section>Edit</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable v-close-popup @click="showClientDeleteModal(props.row)">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showClientDeleteModal(props.row)"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="delete" />
|
||||
</q-item-section>
|
||||
@@ -105,13 +135,18 @@ import SitesTable from "@/components/clients/SitesTable";
|
||||
const columns = [
|
||||
{ name: "name", label: "Name", field: "name", align: "left" },
|
||||
{ name: "sites", label: "Sites", field: "sites", align: "left" },
|
||||
{ name: "agent_count", label: "Total Agents", field: "agent_count", align: "left" },
|
||||
{
|
||||
name: "agent_count",
|
||||
label: "Total Agents",
|
||||
field: "agent_count",
|
||||
align: "left",
|
||||
},
|
||||
];
|
||||
|
||||
export default {
|
||||
name: "ClientsManager",
|
||||
emits: [...useDialogPluginComponent.emits],
|
||||
setup(props) {
|
||||
setup() {
|
||||
// setup quasar dialog
|
||||
const $q = useQuasar();
|
||||
const { dialogRef, onDialogHide } = useDialogPluginComponent();
|
||||
|
@@ -10,7 +10,8 @@
|
||||
</q-bar>
|
||||
<q-form @submit="submit">
|
||||
<q-card-section v-if="siteOptions.length === 0">
|
||||
There are no valid sites to move agents to. Add another site and try again
|
||||
There are no valid sites to move agents to. Add another site and try
|
||||
again
|
||||
</q-card-section>
|
||||
<q-card-section v-if="siteOptions.length > 0">
|
||||
<tactical-dropdown
|
||||
@@ -19,7 +20,10 @@
|
||||
v-model="site"
|
||||
:options="siteOptions"
|
||||
mapOptions
|
||||
:rules="[val => !!val || 'Select the site that the agents should be moved to']"
|
||||
:rules="[
|
||||
(val) =>
|
||||
!!val || 'Select the site that the agents should be moved to',
|
||||
]"
|
||||
hint="The client you are deleting has agents assigned to it. Select a Site below to move the agents to."
|
||||
filterable
|
||||
/>
|
||||
@@ -84,7 +88,9 @@ export default {
|
||||
try {
|
||||
const result =
|
||||
props.type === "client"
|
||||
? await removeClient(props.object.id, { move_to_site: site.value })
|
||||
? await removeClient(props.object.id, {
|
||||
move_to_site: site.value,
|
||||
})
|
||||
: await removeSite(props.object.id, { move_to_site: site.value });
|
||||
notifySuccess(result);
|
||||
onDialogOK();
|
||||
@@ -102,10 +108,19 @@ export default {
|
||||
|
||||
if (props.type === "client") {
|
||||
// filter out client that is being deleted
|
||||
siteOptions.value = Object.freeze(formatSiteOptions(clients.filter(client => client.id !== props.object.id)));
|
||||
siteOptions.value = Object.freeze(
|
||||
formatSiteOptions(
|
||||
clients.filter((client) => client.id !== props.object.id)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
// filter out site that is being dleted
|
||||
clients.forEach(client => (client.sites = client.sites.filter(site => site.id !== props.object.id)));
|
||||
clients.forEach(
|
||||
(client) =>
|
||||
(client.sites = client.sites.filter(
|
||||
(site) => site.id !== props.object.id
|
||||
))
|
||||
);
|
||||
siteOptions.value = Object.freeze(formatSiteOptions(clients));
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,14 @@
|
||||
<q-dialog ref="dialogRef" @hide="onDialogHide">
|
||||
<q-card style="min-width: 70vw; height: 70vh">
|
||||
<q-bar>
|
||||
<q-btn @click="getDeployments" class="q-mr-sm" dense flat push icon="refresh" />
|
||||
<q-btn
|
||||
@click="getDeployments"
|
||||
class="q-mr-sm"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
icon="refresh"
|
||||
/>
|
||||
Manage Deployments
|
||||
<q-space />
|
||||
<q-btn dense flat icon="close" v-close-popup>
|
||||
@@ -11,7 +18,10 @@
|
||||
</q-bar>
|
||||
<q-table
|
||||
dense
|
||||
:table-class="{ 'table-bgcolor': !$q.dark.isActive, 'table-bgcolor-dark': $q.dark.isActive }"
|
||||
:table-class="{
|
||||
'table-bgcolor': !$q.dark.isActive,
|
||||
'table-bgcolor-dark': $q.dark.isActive,
|
||||
}"
|
||||
class="audit-mgr-tbl-sticky"
|
||||
style="max-height: 65vh"
|
||||
binary-state-sort
|
||||
@@ -29,7 +39,11 @@
|
||||
</template>
|
||||
|
||||
<template v-slot:body="props">
|
||||
<q-tr :props="props" class="cursor-pointer" @dblclick="copyLink(props.row)">
|
||||
<q-tr
|
||||
:props="props"
|
||||
class="cursor-pointer"
|
||||
@dblclick="copyLink(props.row)"
|
||||
>
|
||||
<q-menu context-menu auto-close>
|
||||
<q-list dense style="min-width: 200px">
|
||||
<q-item clickable @click="deleteDeployment(props.row)">
|
||||
@@ -48,13 +62,20 @@
|
||||
<q-td key="site" :props="props">{{ props.row.site_name }}</q-td>
|
||||
<q-td key="mon_type" :props="props">{{ props.row.mon_type }}</q-td>
|
||||
<q-td key="arch" :props="props"
|
||||
><span v-if="props.row.arch === '64'">64 bit</span><span v-else>32 bit</span></q-td
|
||||
><span v-if="props.row.arch === '64'">64 bit</span
|
||||
><span v-else>32 bit</span></q-td
|
||||
>
|
||||
<q-td key="expiry" :props="props">{{ formatDate(props.row.expiry) }}</q-td>
|
||||
<q-td key="created" :props="props">{{ formatDate(props.row.created) }}</q-td>
|
||||
<q-td key="expiry" :props="props">{{
|
||||
formatDate(props.row.expiry)
|
||||
}}</q-td>
|
||||
<q-td key="created" :props="props">{{
|
||||
formatDate(props.row.created)
|
||||
}}</q-td>
|
||||
<q-td key="flags" :props="props"
|
||||
><q-badge color="grey-8" label="View Flags" />
|
||||
<q-tooltip style="font-size: 12px">{{ props.row.install_flags }}</q-tooltip>
|
||||
<q-tooltip style="font-size: 12px">{{
|
||||
props.row.install_flags
|
||||
}}</q-tooltip>
|
||||
</q-td>
|
||||
<q-td key="link" :props="props">
|
||||
<q-btn
|
||||
@@ -88,20 +109,50 @@ import NewDeployment from "@/components/clients/NewDeployment";
|
||||
|
||||
// static data
|
||||
const columns = [
|
||||
{ name: "client", label: "Client", field: "client_name", align: "left", sortable: true },
|
||||
{ name: "site", label: "Site", field: "site_name", align: "left", sortable: true },
|
||||
{ name: "mon_type", label: "Type", field: "mon_type", align: "left", sortable: true },
|
||||
{
|
||||
name: "client",
|
||||
label: "Client",
|
||||
field: "client_name",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "site",
|
||||
label: "Site",
|
||||
field: "site_name",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "mon_type",
|
||||
label: "Type",
|
||||
field: "mon_type",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{ name: "arch", label: "Arch", field: "arch", align: "left", sortable: true },
|
||||
{ name: "expiry", label: "Expiry", field: "expiry", align: "left", sortable: true },
|
||||
{ name: "created", label: "Created", field: "created", align: "left", sortable: true },
|
||||
{
|
||||
name: "expiry",
|
||||
label: "Expiry",
|
||||
field: "expiry",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "created",
|
||||
label: "Created",
|
||||
field: "created",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{ name: "flags", label: "Flags", field: "install_flags", align: "left" },
|
||||
{ name: "link", label: "Download Link", align: "left" },
|
||||
];
|
||||
|
||||
export default {
|
||||
name: "Deployment",
|
||||
name: "DeploymentTable",
|
||||
emits: [...useDialogPluginComponent.emits],
|
||||
setup(props) {
|
||||
setup() {
|
||||
// quasar dialog setup
|
||||
const { dialogRef, onDialogHide } = useDialogPluginComponent();
|
||||
const $q = useQuasar();
|
@@ -10,7 +10,7 @@
|
||||
</q-bar>
|
||||
<q-card-section>
|
||||
<tactical-dropdown
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
outlined
|
||||
label="Site"
|
||||
v-model="state.site"
|
||||
@@ -21,11 +21,27 @@
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<div class="q-pl-sm">Agent Type</div>
|
||||
<q-radio v-model="state.agenttype" val="server" label="Server" @update:model-value="power = false" />
|
||||
<q-radio v-model="state.agenttype" val="workstation" label="Workstation" />
|
||||
<q-radio
|
||||
v-model="state.agenttype"
|
||||
val="server"
|
||||
label="Server"
|
||||
@update:model-value="power = false"
|
||||
/>
|
||||
<q-radio
|
||||
v-model="state.agenttype"
|
||||
val="workstation"
|
||||
label="Workstation"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<q-input type="datetime-local" dense label="Expiry" stack-label filled v-model="state.expires" />
|
||||
<q-input
|
||||
type="datetime-local"
|
||||
dense
|
||||
label="Expiry"
|
||||
stack-label
|
||||
filled
|
||||
v-model="state.expires"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section class="q-gutter-sm">
|
||||
<q-checkbox v-model="state.rdp" dense label="Enable RDP" />
|
||||
@@ -44,7 +60,14 @@
|
||||
</q-card-section>
|
||||
<q-card-actions align="right">
|
||||
<q-btn dense flat label="Cancel" v-close-popup />
|
||||
<q-btn :loading="loading" dense flat label="Create" color="primary" @click="submit" />
|
||||
<q-btn
|
||||
:loading="loading"
|
||||
dense
|
||||
flat
|
||||
label="Create"
|
||||
color="primary"
|
||||
@click="submit"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
@@ -57,7 +80,10 @@ import { useDialogPluginComponent, date } from "quasar";
|
||||
import { useSiteDropdown } from "@/composables/clients";
|
||||
import { saveDeployment } from "@/api/clients";
|
||||
import { notifySuccess } from "@/utils/notify";
|
||||
import { formatDateInputField, formatDateStringwithTimezone } from "@/utils/format";
|
||||
import {
|
||||
formatDateInputField,
|
||||
formatDateStringwithTimezone,
|
||||
} from "@/utils/format";
|
||||
|
||||
// ui imports
|
||||
import TacticalDropdown from "@/components/ui/TacticalDropdown";
|
||||
@@ -67,7 +93,7 @@ export default {
|
||||
TacticalDropdown,
|
||||
},
|
||||
emits: [...useDialogPluginComponent.emits],
|
||||
setup(props) {
|
||||
setup() {
|
||||
// setup quasar dialog
|
||||
const { dialogRef, onDialogHide, onDialogOK } = useDialogPluginComponent();
|
||||
|
||||
@@ -94,7 +120,8 @@ export default {
|
||||
...state.value,
|
||||
};
|
||||
|
||||
if (data.expires) data.expires = formatDateStringwithTimezone(data.expires);
|
||||
if (data.expires)
|
||||
data.expires = formatDateStringwithTimezone(data.expires);
|
||||
|
||||
try {
|
||||
const result = await saveDeployment(data);
|
||||
|
@@ -16,22 +16,38 @@
|
||||
:options="clientOptions"
|
||||
outlined
|
||||
mapOptions
|
||||
:rules="[val => !!val || 'Client is required']"
|
||||
:rules="[(val) => !!val || 'Client is required']"
|
||||
filterable
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<q-input :rules="[val => !!val || 'Name is required']" outlined dense v-model="state.name" label="Name" />
|
||||
<q-input
|
||||
:rules="[(val) => !!val || 'Name is required']"
|
||||
outlined
|
||||
dense
|
||||
v-model="state.name"
|
||||
label="Name"
|
||||
/>
|
||||
</q-card-section>
|
||||
|
||||
<div class="q-pl-sm text-h6" v-if="customFields.length > 0">Custom Fields</div>
|
||||
<div class="q-pl-sm text-h6" v-if="customFields.length > 0">
|
||||
Custom Fields
|
||||
</div>
|
||||
<q-card-section v-for="field in customFields" :key="field.id">
|
||||
<CustomField v-model="custom_fields[field.name]" :field="field" />
|
||||
</q-card-section>
|
||||
|
||||
<q-card-actions align="right">
|
||||
<q-btn dense flat push label="Cancel" v-close-popup />
|
||||
<q-btn :loading="loading" dense flat push label="Save" color="primary" type="submit" />
|
||||
<q-btn
|
||||
:loading="loading"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
label="Save"
|
||||
color="primary"
|
||||
type="submit"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-form>
|
||||
</q-card>
|
||||
@@ -72,7 +88,9 @@ export default {
|
||||
const { clientOptions } = useClientDropdown(true);
|
||||
|
||||
// sites for logic
|
||||
const state = !!props.site ? ref(Object.assign({}, props.site)) : ref({ client: props.client, name: "" });
|
||||
const state = !!props.site
|
||||
? ref(Object.assign({}, props.site))
|
||||
: ref({ client: props.client, name: "" });
|
||||
const custom_fields = ref({});
|
||||
const customFields = ref([]);
|
||||
const loading = ref(false);
|
||||
@@ -81,10 +99,15 @@ export default {
|
||||
loading.value = true;
|
||||
const data = {
|
||||
site: state.value,
|
||||
custom_fields: formatCustomFields(customFields.value, custom_fields.value),
|
||||
custom_fields: formatCustomFields(
|
||||
customFields.value,
|
||||
custom_fields.value
|
||||
),
|
||||
};
|
||||
try {
|
||||
const result = !!props.site ? await editSite(props.site.id, data) : await saveSite(data);
|
||||
const result = !!props.site
|
||||
? await editSite(props.site.id, data)
|
||||
: await saveSite(data);
|
||||
notifySuccess(result);
|
||||
onDialogOK();
|
||||
} catch (e) {
|
||||
@@ -98,7 +121,9 @@ export default {
|
||||
const data = await fetchSite(props.site.id);
|
||||
|
||||
for (let field of customFields.value) {
|
||||
const value = data.custom_fields.find(value => value.field === field.id);
|
||||
const value = data.custom_fields.find(
|
||||
(value) => value.field === field.id
|
||||
);
|
||||
|
||||
if (field.type === "multiple") {
|
||||
if (value) custom_fields.value[field.name] = value.value;
|
||||
@@ -118,7 +143,7 @@ export default {
|
||||
$q.loading.show();
|
||||
try {
|
||||
const fields = await fetchCustomFields({ model: "site" });
|
||||
customFields.value = fields.filter(field => !field.hide_in_ui);
|
||||
customFields.value = fields.filter((field) => !field.hide_in_ui);
|
||||
if (props.site) getSiteCustomFieldValues();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
@@ -2,7 +2,14 @@
|
||||
<q-dialog ref="dialogRef" @hide="onDialogHide">
|
||||
<q-card class="q-dialog-plugin" style="width: 60vw">
|
||||
<q-bar>
|
||||
<q-btn @click="getSites" class="q-mr-sm" dense flat push icon="refresh" />Sites for {{ client.name }}
|
||||
<q-btn
|
||||
@click="getSites"
|
||||
class="q-mr-sm"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
icon="refresh"
|
||||
/>Sites for {{ client.name }}
|
||||
<q-space />
|
||||
<q-btn dense flat icon="close" v-close-popup>
|
||||
<q-tooltip class="bg-white text-primary">Close</q-tooltip>
|
||||
@@ -18,13 +25,25 @@
|
||||
virtual-scroll
|
||||
:rows-per-page-options="[0]"
|
||||
no-data-label="No Sites"
|
||||
:table-class="{ 'table-bgcolor': !$q.dark.isActive, 'table-bgcolor-dark': $q.dark.isActive }"
|
||||
:table-class="{
|
||||
'table-bgcolor': !$q.dark.isActive,
|
||||
'table-bgcolor-dark': $q.dark.isActive,
|
||||
}"
|
||||
class="settings-tbl-sticky"
|
||||
style="height: 65vh"
|
||||
:loading="loading"
|
||||
>
|
||||
<template v-slot:top>
|
||||
<q-btn label="New" dense flat push unelevated no-caps icon="add" @click="showAddSite" />
|
||||
<q-btn
|
||||
label="New"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
unelevated
|
||||
no-caps
|
||||
icon="add"
|
||||
@click="showAddSite"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<!-- loading slot -->
|
||||
@@ -34,17 +53,29 @@
|
||||
|
||||
<!-- body slots -->
|
||||
<template v-slot:body="props">
|
||||
<q-tr :props="props" class="cursor-pointer" @dblclick="showEditSite(props.row)">
|
||||
<q-tr
|
||||
:props="props"
|
||||
class="cursor-pointer"
|
||||
@dblclick="showEditSite(props.row)"
|
||||
>
|
||||
<!-- context menu -->
|
||||
<q-menu context-menu>
|
||||
<q-list dense style="min-width: 200px">
|
||||
<q-item clickable v-close-popup @click="showEditSite(props.row)">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showEditSite(props.row)"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="edit" />
|
||||
</q-item-section>
|
||||
<q-item-section>Edit</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable v-close-popup @click="showSiteDeleteModal(props.row)">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="showSiteDeleteModal(props.row)"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="delete" />
|
||||
</q-item-section>
|
||||
@@ -85,7 +116,12 @@ import DeleteClient from "@/components/clients/DeleteClient";
|
||||
// static data
|
||||
const columns = [
|
||||
{ name: "name", label: "Name", field: "name", align: "left" },
|
||||
{ name: "agent_count", label: "Total Agents", field: "agent_count", align: "left" },
|
||||
{
|
||||
name: "agent_count",
|
||||
label: "Total Agents",
|
||||
field: "agent_count",
|
||||
align: "left",
|
||||
},
|
||||
];
|
||||
|
||||
export default {
|
||||
|
@@ -14,7 +14,13 @@
|
||||
</q-card-section>
|
||||
<!-- name -->
|
||||
<q-card-section>
|
||||
<q-input label="Name" outlined dense v-model="localKey.name" :rules="[val => !!val || '*Required']" />
|
||||
<q-input
|
||||
label="Name"
|
||||
outlined
|
||||
dense
|
||||
v-model="localKey.name"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
/>
|
||||
</q-card-section>
|
||||
|
||||
<!-- user -->
|
||||
@@ -48,7 +54,13 @@
|
||||
|
||||
<q-card-actions align="right">
|
||||
<q-btn flat label="Cancel" v-close-popup />
|
||||
<q-btn flat label="Submit" color="primary" type="submit" :loading="loading" />
|
||||
<q-btn
|
||||
flat
|
||||
label="Submit"
|
||||
color="primary"
|
||||
type="submit"
|
||||
:loading="loading"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-form>
|
||||
</q-card>
|
||||
@@ -62,7 +74,10 @@ import { useDialogPluginComponent } from "quasar";
|
||||
import { saveAPIKey, editAPIKey } from "@/api/accounts";
|
||||
import { useUserDropdown } from "@/composables/accounts";
|
||||
import { notifySuccess } from "@/utils/notify";
|
||||
import { formatDateInputField, formatDateStringwithTimezone } from "@/utils/format";
|
||||
import {
|
||||
formatDateInputField,
|
||||
formatDateStringwithTimezone,
|
||||
} from "@/utils/format";
|
||||
|
||||
// ui imports
|
||||
import TacticalDropdown from "@/components/ui/TacticalDropdown.vue";
|
||||
@@ -80,7 +95,9 @@ export default {
|
||||
const { userOptions } = useUserDropdown(true);
|
||||
|
||||
// setup api key form logic
|
||||
const key = props.APIKey ? ref(Object.assign({}, props.APIKey)) : ref({ name: "", expiration: null });
|
||||
const key = props.APIKey
|
||||
? ref(Object.assign({}, props.APIKey))
|
||||
: ref({ name: "", expiration: null });
|
||||
const loading = ref(false);
|
||||
|
||||
// remove Z from date string
|
||||
@@ -88,7 +105,9 @@ export default {
|
||||
key.value.expiration = formatDateInputField(key.value.expiration);
|
||||
}
|
||||
|
||||
const title = computed(() => (props.APIKey ? "Edit API Key" : "Add API Key"));
|
||||
const title = computed(() =>
|
||||
props.APIKey ? "Edit API Key" : "Add API Key"
|
||||
);
|
||||
|
||||
async function submitForm() {
|
||||
loading.value = true;
|
||||
@@ -98,10 +117,13 @@ export default {
|
||||
};
|
||||
|
||||
// convert date to local timezone if exists
|
||||
if (data.expiration) data.expiration = formatDateStringwithTimezone(data.expiration);
|
||||
if (data.expiration)
|
||||
data.expiration = formatDateStringwithTimezone(data.expiration);
|
||||
|
||||
try {
|
||||
const result = props.APIKey ? await editAPIKey(data) : await saveAPIKey(data);
|
||||
const result = props.APIKey
|
||||
? await editAPIKey(data)
|
||||
: await saveAPIKey(data);
|
||||
onDialogOK();
|
||||
notifySuccess(result);
|
||||
loading.value = false;
|
||||
|
@@ -3,7 +3,14 @@
|
||||
<div class="row">
|
||||
<div class="text-subtitle2">API Keys</div>
|
||||
<q-space />
|
||||
<q-btn size="sm" color="grey-5" icon="fas fa-plus" text-color="black" label="Add key" @click="addAPIKey" />
|
||||
<q-btn
|
||||
size="sm"
|
||||
color="grey-5"
|
||||
icon="fas fa-plus"
|
||||
text-color="black"
|
||||
label="Add key"
|
||||
@click="addAPIKey"
|
||||
/>
|
||||
</div>
|
||||
<q-separator />
|
||||
<q-table
|
||||
@@ -25,7 +32,11 @@
|
||||
|
||||
<!-- body slots -->
|
||||
<template v-slot:body="props">
|
||||
<q-tr :props="props" class="cursor-pointer" @dblclick="editAPIKey(props.row)">
|
||||
<q-tr
|
||||
:props="props"
|
||||
class="cursor-pointer"
|
||||
@dblclick="editAPIKey(props.row)"
|
||||
>
|
||||
<!-- context menu -->
|
||||
<q-menu context-menu>
|
||||
<q-list dense style="min-width: 200px">
|
||||
@@ -65,7 +76,11 @@
|
||||
{{ formatDate(props.row.created_time) }}
|
||||
</q-td>
|
||||
<q-td>
|
||||
<q-icon size="sm" name="content_copy" @click="copyKeyToClipboard(props.row.key)">
|
||||
<q-icon
|
||||
size="sm"
|
||||
name="content_copy"
|
||||
@click="copyKeyToClipboard(props.row.key)"
|
||||
>
|
||||
<q-tooltip>Copy API Key to clipboard</q-tooltip>
|
||||
</q-icon>
|
||||
</q-td>
|
||||
|
@@ -1,8 +1,18 @@
|
||||
<template>
|
||||
<q-dialog ref="dialog" @hide="onHide">
|
||||
<q-card class="q-dialog-plugin" style="min-width: 80vw; min-height: 65vh; overflow-x: hidden">
|
||||
<q-card
|
||||
class="q-dialog-plugin"
|
||||
style="min-width: 80vw; min-height: 65vh; overflow-x: hidden"
|
||||
>
|
||||
<q-bar>
|
||||
<q-btn @click="getChartData" class="q-mr-sm" dense flat push icon="refresh" />
|
||||
<q-btn
|
||||
@click="getChartData"
|
||||
class="q-mr-sm"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
icon="refresh"
|
||||
/>
|
||||
{{ title }}
|
||||
<q-space />
|
||||
<q-btn dense flat icon="close" v-close-popup>
|
||||
@@ -112,11 +122,13 @@ export default {
|
||||
seriesName() {
|
||||
if (this.check.check_type === "cpuload") return "CPU Load";
|
||||
else if (this.check.check_type === "memory") return "Memory Usage";
|
||||
else if (this.check.check_type === "diskspace") return "Disk Space Remaining";
|
||||
else if (this.check.check_type === "diskspace")
|
||||
return "Disk Space Remaining";
|
||||
else if (this.check.check_type === "script") return "Script Results";
|
||||
else if (this.check.check_type === "eventlog") return "Status";
|
||||
else if (this.check.check_type === "winsvc") return "Status";
|
||||
else if (this.check.check_type === "ping") return "Status";
|
||||
else return "";
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
@@ -124,8 +136,10 @@ export default {
|
||||
this.$q.loading.show();
|
||||
|
||||
this.$axios
|
||||
.patch(`/checks/${this.check.check_result.id}/history/`, { timeFilter: this.timeFilter })
|
||||
.then(r => {
|
||||
.patch(`/checks/${this.check.check_result.id}/history/`, {
|
||||
timeFilter: this.timeFilter,
|
||||
})
|
||||
.then((r) => {
|
||||
this.history = Object.freeze(r.data);
|
||||
|
||||
// save copy of data to reference results in chart tooltip
|
||||
@@ -139,7 +153,7 @@ export default {
|
||||
|
||||
this.$q.loading.hide();
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
@@ -208,7 +222,7 @@ export default {
|
||||
min: 0,
|
||||
max: 100,
|
||||
labels: {
|
||||
formatter: (val, index) => {
|
||||
formatter: (val) => {
|
||||
return val + "%";
|
||||
},
|
||||
},
|
||||
@@ -227,7 +241,7 @@ export default {
|
||||
forceNiceScale: true,
|
||||
labels: {
|
||||
minWidth: 50,
|
||||
formatter: (val, index) => {
|
||||
formatter: (val) => {
|
||||
if (val === 0) return "Passing";
|
||||
else if (val === 1) return "Failing";
|
||||
else return "";
|
||||
@@ -238,17 +252,29 @@ export default {
|
||||
// customize the yaxis tooltip to include more information
|
||||
this.chartOptions["tooltip"]["y"] = {
|
||||
title: {
|
||||
formatter: val => {
|
||||
formatter: () => {
|
||||
return "";
|
||||
},
|
||||
},
|
||||
formatter: (value, { series, seriesIndex, dataPointIndex, w }) => {
|
||||
formatter: (value, { dataPointIndex }) => {
|
||||
let formatted = "";
|
||||
if (this.check.check_type === "script") {
|
||||
formatted += "Return Code: " + this.results[dataPointIndex].results.retcode + "<br/>";
|
||||
formatted += "Std Out: " + this.results[dataPointIndex].results.stdout + "<br/>";
|
||||
formatted += "Err Out: " + this.results[dataPointIndex].results.errout + "<br/>";
|
||||
formatted += "Execution Time: " + this.results[dataPointIndex].results.execution_time + "<br/>";
|
||||
formatted +=
|
||||
"Return Code: " +
|
||||
this.results[dataPointIndex].results.retcode +
|
||||
"<br/>";
|
||||
formatted +=
|
||||
"Std Out: " +
|
||||
this.results[dataPointIndex].results.stdout +
|
||||
"<br/>";
|
||||
formatted +=
|
||||
"Err Out: " +
|
||||
this.results[dataPointIndex].results.errout +
|
||||
"<br/>";
|
||||
formatted +=
|
||||
"Execution Time: " +
|
||||
this.results[dataPointIndex].results.execution_time +
|
||||
"<br/>";
|
||||
} else {
|
||||
formatted += this.results[dataPointIndex].results;
|
||||
}
|
||||
|
@@ -14,8 +14,13 @@
|
||||
:rows="auditLogs"
|
||||
:columns="columns"
|
||||
class="tabs-tbl-sticky"
|
||||
:table-class="{ 'table-bgcolor': !$q.dark.isActive, 'table-bgcolor-dark': $q.dark.isActive }"
|
||||
:style="{ 'max-height': tabHeight ? tabHeight : `${$q.screen.height - 33}px` }"
|
||||
:table-class="{
|
||||
'table-bgcolor': !$q.dark.isActive,
|
||||
'table-bgcolor-dark': $q.dark.isActive,
|
||||
}"
|
||||
:style="{
|
||||
'max-height': tabHeight ? tabHeight : `${$q.screen.height - 33}px`,
|
||||
}"
|
||||
row-key="id"
|
||||
dense
|
||||
binary-state-sort
|
||||
@@ -27,7 +32,15 @@
|
||||
:loading="loading"
|
||||
>
|
||||
<template v-slot:top>
|
||||
<q-btn v-if="agent" class="q-pr-sm" dense flat push @click="search" icon="refresh" />
|
||||
<q-btn
|
||||
v-if="agent"
|
||||
class="q-pr-sm"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
@click="search"
|
||||
icon="refresh"
|
||||
/>
|
||||
<q-option-group
|
||||
v-if="!agent"
|
||||
class="q-pr-sm"
|
||||
@@ -111,7 +124,10 @@
|
||||
<template v-slot:body-cell-action="props">
|
||||
<q-td :props="props">
|
||||
<div>
|
||||
<q-badge :color="formatActionColor(props.value)" :label="props.value" />
|
||||
<q-badge
|
||||
:color="formatActionColor(props.value)"
|
||||
:label="props.value"
|
||||
/>
|
||||
</div>
|
||||
</q-td>
|
||||
</template>
|
||||
@@ -160,9 +176,27 @@ const columns = [
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{ name: "username", label: "Username", field: "username", align: "left", sortable: true },
|
||||
{ name: "agent", label: "Agent", field: "agent", align: "left", sortable: true },
|
||||
{ name: "client", label: "Client", field: "site", align: "left", sortable: true },
|
||||
{
|
||||
name: "username",
|
||||
label: "Username",
|
||||
field: "username",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "agent",
|
||||
label: "Agent",
|
||||
field: "agent",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "client",
|
||||
label: "Client",
|
||||
field: "site",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{ name: "site", label: "Site", field: "site", align: "left", sortable: true },
|
||||
{
|
||||
name: "action",
|
||||
@@ -170,7 +204,7 @@ const columns = [
|
||||
field: "action",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
format: (val, row) => formatTableColumnText(val),
|
||||
format: (val) => formatTableColumnText(val),
|
||||
},
|
||||
{
|
||||
name: "object_type",
|
||||
@@ -178,10 +212,22 @@ const columns = [
|
||||
field: "object_type",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
format: (val, row) => formatTableColumnText(val),
|
||||
format: (val) => formatTableColumnText(val),
|
||||
},
|
||||
{
|
||||
name: "message",
|
||||
label: "Message",
|
||||
field: "message",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "client_ip",
|
||||
label: "Client IP",
|
||||
field: "ip_address",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{ name: "message", label: "Message", field: "message", align: "left", sortable: true },
|
||||
{ name: "client_ip", label: "Client IP", field: "ip_address", align: "left", sortable: true },
|
||||
];
|
||||
|
||||
const agentActionOptions = [
|
||||
@@ -292,12 +338,17 @@ export default {
|
||||
pagination: pagination.value,
|
||||
};
|
||||
|
||||
if (agentFilter.value && agentFilter.value.length > 0) data["agentFilter"] = agentFilter.value;
|
||||
else if (clientFilter.value && clientFilter.value.length > 0) data["clientFilter"] = clientFilter.value;
|
||||
if (userFilter.value && userFilter.value.length > 0) data["userFilter"] = userFilter.value;
|
||||
if (agentFilter.value && agentFilter.value.length > 0)
|
||||
data["agentFilter"] = agentFilter.value;
|
||||
else if (clientFilter.value && clientFilter.value.length > 0)
|
||||
data["clientFilter"] = clientFilter.value;
|
||||
if (userFilter.value && userFilter.value.length > 0)
|
||||
data["userFilter"] = userFilter.value;
|
||||
if (timeFilter.value) data["timeFilter"] = timeFilter.value;
|
||||
if (actionFilter.value && actionFilter.value.length > 0) data["actionFilter"] = actionFilter.value;
|
||||
if (objectFilter.value && objectFilter.value.length > 0) data["objectFilter"] = objectFilter.value;
|
||||
if (actionFilter.value && actionFilter.value.length > 0)
|
||||
data["actionFilter"] = actionFilter.value;
|
||||
if (objectFilter.value && objectFilter.value.length > 0)
|
||||
data["objectFilter"] = objectFilter.value;
|
||||
try {
|
||||
const { audit_logs, total } = await fetchAuditLog(data);
|
||||
auditLogs.value = audit_logs;
|
||||
@@ -349,7 +400,7 @@ export default {
|
||||
watch([userFilter, actionFilter, timeFilter], search);
|
||||
watch(
|
||||
() => props.agent,
|
||||
(newValue, oldValue) => {
|
||||
(newValue) => {
|
||||
if (newValue) {
|
||||
agentFilter.value = [props.agent];
|
||||
search();
|
||||
@@ -389,14 +440,18 @@ export default {
|
||||
clientOptions,
|
||||
agentOptions,
|
||||
columns,
|
||||
actionOptions: props.agent ? [...agentActionOptions] : [...agentActionOptions, ...actionOptions],
|
||||
actionOptions: props.agent
|
||||
? [...agentActionOptions]
|
||||
: [...agentActionOptions, ...actionOptions],
|
||||
objectOptions,
|
||||
timeOptions,
|
||||
filterTypeOptions,
|
||||
|
||||
//computed
|
||||
tableNoDataText: computed(() =>
|
||||
searched.value ? "No data found. Try to refine you search" : "Click search to find audit logs"
|
||||
searched.value
|
||||
? "No data found. Try to refine you search"
|
||||
: "Click search to find audit logs"
|
||||
),
|
||||
|
||||
// methods
|
||||
|
@@ -1,16 +1,28 @@
|
||||
<template>
|
||||
<q-card>
|
||||
<q-bar v-if="modal">
|
||||
<q-btn @click="getDebugLog" class="q-mr-sm" dense flat push icon="refresh" />Debug Log
|
||||
<q-btn
|
||||
@click="getDebugLog"
|
||||
class="q-mr-sm"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
icon="refresh"
|
||||
/>Debug Log
|
||||
<q-space />
|
||||
<q-btn dense flat icon="close" v-close-popup>
|
||||
<q-tooltip content-class="bg-white text-primary">Close</q-tooltip>
|
||||
</q-btn>
|
||||
</q-bar>
|
||||
<q-table
|
||||
:table-class="{ 'table-bgcolor': !$q.dark.isActive, 'table-bgcolor-dark': $q.dark.isActive }"
|
||||
:table-class="{
|
||||
'table-bgcolor': !$q.dark.isActive,
|
||||
'table-bgcolor-dark': $q.dark.isActive,
|
||||
}"
|
||||
class="tabs-tbl-sticky"
|
||||
:style="{ 'max-height': tabHeight ? tabHeight : `${$q.screen.height - 33}px` }"
|
||||
:style="{
|
||||
'max-height': tabHeight ? tabHeight : `${$q.screen.height - 33}px`,
|
||||
}"
|
||||
:rows="debugLog"
|
||||
:columns="columns"
|
||||
:title="modal ? 'Debug Logs' : ''"
|
||||
@@ -23,7 +35,15 @@
|
||||
:rows-per-page-options="[0]"
|
||||
>
|
||||
<template v-slot:top>
|
||||
<q-btn v-if="agent" class="q-pr-sm" dense flat push @click="getDebugLog" icon="refresh" />
|
||||
<q-btn
|
||||
v-if="agent"
|
||||
class="q-pr-sm"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
@click="getDebugLog"
|
||||
icon="refresh"
|
||||
/>
|
||||
<tactical-dropdown
|
||||
v-if="!agent"
|
||||
class="q-pr-sm"
|
||||
@@ -46,12 +66,39 @@
|
||||
outlined
|
||||
clearable
|
||||
/>
|
||||
<q-radio v-model="logLevelFilter" color="cyan" val="info" label="Info" />
|
||||
<q-radio v-model="logLevelFilter" color="red" val="critical" label="Critical" />
|
||||
<q-radio v-model="logLevelFilter" color="red" val="error" label="Error" />
|
||||
<q-radio v-model="logLevelFilter" color="yellow" val="warning" label="Warning" />
|
||||
<q-radio
|
||||
v-model="logLevelFilter"
|
||||
color="cyan"
|
||||
val="info"
|
||||
label="Info"
|
||||
/>
|
||||
<q-radio
|
||||
v-model="logLevelFilter"
|
||||
color="red"
|
||||
val="critical"
|
||||
label="Critical"
|
||||
/>
|
||||
<q-radio
|
||||
v-model="logLevelFilter"
|
||||
color="red"
|
||||
val="error"
|
||||
label="Error"
|
||||
/>
|
||||
<q-radio
|
||||
v-model="logLevelFilter"
|
||||
color="yellow"
|
||||
val="warning"
|
||||
label="Warning"
|
||||
/>
|
||||
<q-space />
|
||||
<q-input v-model="filter" outlined label="Search" dense clearable class="q-pr-sm">
|
||||
<q-input
|
||||
v-model="filter"
|
||||
outlined
|
||||
label="Search"
|
||||
dense
|
||||
clearable
|
||||
class="q-pr-sm"
|
||||
>
|
||||
<template v-slot:prepend>
|
||||
<q-icon name="search" color="primary" />
|
||||
</template>
|
||||
@@ -79,7 +126,7 @@
|
||||
|
||||
<script>
|
||||
// composition api
|
||||
import { ref, watch, computed, onMounted } from "vue";
|
||||
import { ref, toRef, watch, computed, onMounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import { useAgentDropdown } from "@/composables/agents";
|
||||
import { fetchDebugLog } from "@/api/logs";
|
||||
@@ -106,17 +153,35 @@ const columns = [
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{ name: "log_level", label: "Log Level", field: "log_level", align: "left", sortable: true },
|
||||
{ name: "agent", label: "Agent", field: "agent", align: "left", sortable: true },
|
||||
{
|
||||
name: "log_level",
|
||||
label: "Log Level",
|
||||
field: "log_level",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "agent",
|
||||
label: "Agent",
|
||||
field: "agent",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "log_type",
|
||||
label: "Log Type",
|
||||
field: "log_type",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
format: (val, row) => formatTableColumnText(val),
|
||||
format: (val) => formatTableColumnText(val),
|
||||
},
|
||||
{
|
||||
name: "message",
|
||||
label: "Message",
|
||||
field: "message",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{ name: "message", label: "Message", field: "message", align: "left", sortable: true },
|
||||
];
|
||||
|
||||
export default {
|
||||
@@ -144,7 +209,7 @@ export default {
|
||||
|
||||
// set main debug log functionality
|
||||
const debugLog = ref([]);
|
||||
const agentFilter = ref(null);
|
||||
const agentFilter = props.agent ? toRef(props, "agent") : ref(null);
|
||||
const logLevelFilter = ref("info");
|
||||
const logTypeFilter = ref(null);
|
||||
const loading = ref(false);
|
||||
@@ -167,10 +232,9 @@ export default {
|
||||
}
|
||||
|
||||
if (props.agent) {
|
||||
agentFilter.value = props.agent;
|
||||
watch(
|
||||
() => props.agent,
|
||||
(newValue, oldValue) => {
|
||||
(newValue) => {
|
||||
if (newValue) {
|
||||
agentFilter.value = props.agent;
|
||||
getDebugLog();
|
||||
|
@@ -2,14 +2,28 @@
|
||||
<q-dialog ref="dialogRef" @hide="onDialogHide">
|
||||
<q-card class="q-dialog-plugin" style="height: 70vh; min-width: 70vw">
|
||||
<q-bar>
|
||||
<q-btn @click="getPendingActions" class="q-mr-sm" dense flat push icon="refresh" />
|
||||
{{ agent ? `Pending Actions for ${agent.hostname}` : "All Pending Actions" }}
|
||||
<q-btn
|
||||
@click="getPendingActions"
|
||||
class="q-mr-sm"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
icon="refresh"
|
||||
/>
|
||||
{{
|
||||
agent
|
||||
? `Pending Actions for ${agent.hostname}`
|
||||
: "All Pending Actions"
|
||||
}}
|
||||
<q-space />
|
||||
<q-btn dense flat icon="close" v-close-popup />
|
||||
</q-bar>
|
||||
<q-table
|
||||
dense
|
||||
:table-class="{ 'table-bgcolor': !$q.dark.isActive, 'table-bgcolor-dark': $q.dark.isActive }"
|
||||
:table-class="{
|
||||
'table-bgcolor': !$q.dark.isActive,
|
||||
'table-bgcolor-dark': $q.dark.isActive,
|
||||
}"
|
||||
class="remote-bg-tbl-sticky"
|
||||
style="max-height: 65vh"
|
||||
:rows="filteredActions"
|
||||
@@ -25,7 +39,11 @@
|
||||
<template v-slot:top>
|
||||
<q-space />
|
||||
<q-btn
|
||||
:label="showCompleted ? `Hide ${completedCount} Completed` : `Show ${completedCount} Completed`"
|
||||
:label="
|
||||
showCompleted
|
||||
? `Hide ${completedCount} Completed`
|
||||
: `Show ${completedCount} Completed`
|
||||
"
|
||||
:icon="showCompleted ? 'visibility_off' : 'visibility'"
|
||||
@click="showCompleted = !showCompleted"
|
||||
dense
|
||||
@@ -38,7 +56,10 @@
|
||||
<q-menu context-menu auto-close>
|
||||
<q-list dense>
|
||||
<q-item
|
||||
:disable="props.row.status === 'completed' || props.row.action_type === 'agentinstall'"
|
||||
:disable="
|
||||
props.row.status === 'completed' ||
|
||||
props.row.action_type === 'agentinstall'
|
||||
"
|
||||
clickable
|
||||
@click="cancelPendingAction(props.row)"
|
||||
>
|
||||
@@ -63,9 +84,13 @@
|
||||
<q-icon name="download" size="sm" />
|
||||
</q-td>
|
||||
<q-td v-if="props.row.status !== 'completed'">
|
||||
<span v-if="props.row.action_type === 'agentupdate'">{{ getNextAgentUpdateTime() }}</span>
|
||||
<span v-if="props.row.action_type === 'agentupdate'">{{
|
||||
getNextAgentUpdateTime()
|
||||
}}</span>
|
||||
<span v-else>{{
|
||||
props.row.action_type === "schedreboot" ? formatDate(props.row.due) : props.row.due
|
||||
props.row.action_type === "schedreboot"
|
||||
? formatDate(props.row.due)
|
||||
: props.row.due
|
||||
}}</span>
|
||||
</q-td>
|
||||
<q-td v-else>Completed</q-td>
|
||||
@@ -73,7 +98,12 @@
|
||||
<q-td v-if="!agent">{{ props.row.hostname }}</q-td>
|
||||
<q-td v-if="!agent">{{ props.row.client }}</q-td>
|
||||
<q-td v-if="!agent">{{ props.row.site }}</q-td>
|
||||
<q-td v-if="props.row.action_type === 'chocoinstall' && props.row.status === 'completed'">
|
||||
<q-td
|
||||
v-if="
|
||||
props.row.action_type === 'chocoinstall' &&
|
||||
props.row.status === 'completed'
|
||||
"
|
||||
>
|
||||
<q-btn
|
||||
color="primary"
|
||||
icon="preview"
|
||||
@@ -95,7 +125,11 @@
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import { useStore } from "vuex";
|
||||
import { useQuasar, useDialogPluginComponent } from "quasar";
|
||||
import { fetchPendingActions, fetchAgentPendingActions, deletePendingAction } from "@/api/logs";
|
||||
import {
|
||||
fetchPendingActions,
|
||||
fetchAgentPendingActions,
|
||||
deletePendingAction,
|
||||
} from "@/api/logs";
|
||||
import { getNextAgentUpdateTime } from "@/utils/format";
|
||||
import { notifySuccess } from "@/utils/notify";
|
||||
|
||||
@@ -103,11 +137,35 @@ import { notifySuccess } from "@/utils/notify";
|
||||
const columns = [
|
||||
{ name: "id", field: "id" },
|
||||
{ name: "status", field: "status" },
|
||||
{ name: "type", label: "Type", field: "action_type", align: "left", sortable: true },
|
||||
{
|
||||
name: "type",
|
||||
label: "Type",
|
||||
field: "action_type",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{ name: "due", label: "Due", field: "due", align: "left", sortable: true },
|
||||
{ name: "desc", label: "Description", field: "description", align: "left", sortable: true },
|
||||
{ name: "agent", label: "Agent", field: "hostname", align: "left", sortable: true },
|
||||
{ name: "client", label: "Client", field: "client", align: "left", sortable: true },
|
||||
{
|
||||
name: "desc",
|
||||
label: "Description",
|
||||
field: "description",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "agent",
|
||||
label: "Agent",
|
||||
field: "hostname",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "client",
|
||||
label: "Client",
|
||||
field: "client",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{ name: "site", label: "Site", field: "site", align: "left", sortable: true },
|
||||
{ name: "details", field: "details", align: "left", sortable: false },
|
||||
];
|
||||
@@ -133,7 +191,8 @@ export default {
|
||||
const loading = ref(false);
|
||||
const completedCount = computed(() => {
|
||||
try {
|
||||
return actions.value.filter(action => action.status === "completed").length;
|
||||
return actions.value.filter((action) => action.status === "completed")
|
||||
.length;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return 0;
|
||||
@@ -147,7 +206,8 @@ export default {
|
||||
|
||||
const filteredActions = computed(() => {
|
||||
if (showCompleted.value) return actions.value;
|
||||
else return actions.value.filter(action => action.status !== "completed");
|
||||
else
|
||||
return actions.value.filter((action) => action.status !== "completed");
|
||||
});
|
||||
|
||||
function showOutput(details) {
|
||||
|
@@ -15,7 +15,7 @@
|
||||
outlined
|
||||
dense
|
||||
v-model="localUser.username"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
class="q-pa-none"
|
||||
/>
|
||||
</div>
|
||||
@@ -28,7 +28,7 @@
|
||||
dense
|
||||
v-model="localUser.password"
|
||||
:type="isPwd ? 'password' : 'text'"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
class="q-pa-none"
|
||||
>
|
||||
<template v-slot:append>
|
||||
@@ -48,7 +48,7 @@
|
||||
outlined
|
||||
dense
|
||||
v-model="localUser.email"
|
||||
:rules="[val => isValidEmail(val) || 'Invalid email']"
|
||||
:rules="[(val) => isValidEmail(val) || 'Invalid email']"
|
||||
class="q-pa-none"
|
||||
/>
|
||||
</div>
|
||||
@@ -68,13 +68,19 @@
|
||||
<q-card-section class="row">
|
||||
<div class="col-2">Active:</div>
|
||||
<div class="col-10">
|
||||
<q-checkbox v-model="localUser.is_active" :disable="localUser.username === logged_in_user" />
|
||||
<q-checkbox
|
||||
v-model="localUser.is_active"
|
||||
:disable="localUser.username === logged_in_user"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
<q-card-section class="row">
|
||||
<div class="col-2">Role:</div>
|
||||
<template v-if="roles.length === 0"
|
||||
><span>No roles have been created. Create some from Settings > Permissions Manager</span></template
|
||||
><span
|
||||
>No roles have been created. Create some from Settings >
|
||||
Permissions Manager</span
|
||||
></template
|
||||
>
|
||||
<template v-else
|
||||
><q-select
|
||||
@@ -97,7 +103,12 @@
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section class="row items-center">
|
||||
<q-btn :disable="!disableSave" label="Save" color="primary" type="submit" />
|
||||
<q-btn
|
||||
:disable="!disableSave"
|
||||
label="Save"
|
||||
color="primary"
|
||||
type="submit"
|
||||
/>
|
||||
</q-card-section>
|
||||
</q-form>
|
||||
</q-card>
|
||||
@@ -135,17 +146,17 @@ export default {
|
||||
return this.user ? "Edit User" : "Add User";
|
||||
},
|
||||
...mapState({
|
||||
logged_in_user: state => state.username,
|
||||
logged_in_user: (state) => state.username,
|
||||
}),
|
||||
},
|
||||
methods: {
|
||||
getRoles() {
|
||||
this.$axios
|
||||
.get("/accounts/roles/")
|
||||
.then(r => {
|
||||
this.roles = r.data.map(role => ({ label: role.name, value: role.id }));
|
||||
})
|
||||
.catch(() => {});
|
||||
this.$axios.get("/accounts/roles/").then((r) => {
|
||||
this.roles = r.data.map((role) => ({
|
||||
label: role.name,
|
||||
value: role.id,
|
||||
}));
|
||||
});
|
||||
},
|
||||
onSubmit() {
|
||||
this.$q.loading.show();
|
||||
@@ -171,7 +182,7 @@ export default {
|
||||
} else {
|
||||
this.$axios
|
||||
.post("/accounts/users/", this.localUser)
|
||||
.then(r => {
|
||||
.then((r) => {
|
||||
this.$q.loading.hide();
|
||||
this.onOk();
|
||||
this.notifySuccess(`User ${r.data} was added!`);
|
||||
|
@@ -15,7 +15,7 @@
|
||||
dense
|
||||
v-model="password"
|
||||
:type="isPwd ? 'password' : 'text'"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
>
|
||||
<template v-slot:append>
|
||||
<q-icon
|
||||
@@ -59,12 +59,12 @@ export default {
|
||||
|
||||
this.$axios
|
||||
.post("/accounts/users/reset/", data)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.onOk();
|
||||
this.$q.loading.hide();
|
||||
this.notifySuccess("User Password Reset!");
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
|
@@ -11,7 +11,8 @@
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<p class="text-subtitle1">
|
||||
Download the agent then run the following command from an elevated command prompt on the device you want to add.
|
||||
Download the agent then run the following command from an elevated
|
||||
command prompt on the device you want to add.
|
||||
</p>
|
||||
<p>
|
||||
<q-field outlined :color="$q.dark.isActive ? 'white' : 'black'">
|
||||
@@ -38,15 +39,23 @@
|
||||
</div>
|
||||
<div class="q-pa-xs q-gutter-xs">
|
||||
<q-badge class="text-caption q-mr-xs" color="grey" text-color="black">
|
||||
<code>-local-mesh "C:\\<some folder or path>\\meshagent.exe"</code>
|
||||
<code
|
||||
>-local-mesh "C:\\<some folder or
|
||||
path>\\meshagent.exe"</code
|
||||
>
|
||||
</q-badge>
|
||||
<span> To skip downloading the Mesh Agent during the install.</span>
|
||||
</div>
|
||||
<div class="q-pa-xs q-gutter-xs">
|
||||
<q-badge class="text-caption q-mr-xs" color="grey" text-color="black">
|
||||
<code>-meshdir "C:\Program Files\Your Company Name\Mesh Agent"</code>
|
||||
<code
|
||||
>-meshdir "C:\Program Files\Your Company Name\Mesh Agent"</code
|
||||
>
|
||||
</q-badge>
|
||||
<span>Specify full path to the directory containing MeshAgent.exe if using custom agent branding</span>
|
||||
<span
|
||||
>Specify full path to the directory containing MeshAgent.exe if
|
||||
using custom agent branding</span
|
||||
>
|
||||
</div>
|
||||
<div class="q-pa-xs q-gutter-xs">
|
||||
<q-badge class="text-caption q-mr-xs" color="grey" text-color="black">
|
||||
@@ -74,8 +83,15 @@
|
||||
</div>
|
||||
</q-expansion-item>
|
||||
<br />
|
||||
<p class="text-italic">Note: the auth token above will be valid for {{ info.expires }} hours.</p>
|
||||
<q-btn type="a" :href="info.data.url" color="primary" label="Download Agent" />
|
||||
<p class="text-italic">
|
||||
Note: the auth token above will be valid for {{ info.expires }} hours.
|
||||
</p>
|
||||
<q-btn
|
||||
type="a"
|
||||
:href="info.data.url"
|
||||
color="primary"
|
||||
label="Download Agent"
|
||||
/>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</template>
|
||||
|
@@ -12,18 +12,32 @@
|
||||
<q-card-section>
|
||||
<div class="q-gutter-sm">
|
||||
<q-radio dense v-model="state.mode" val="mesh" label="Mesh Agent" />
|
||||
<q-radio dense v-model="state.mode" val="tacagent" label="Tactical Agent" />
|
||||
<q-radio
|
||||
dense
|
||||
v-model="state.mode"
|
||||
val="tacagent"
|
||||
label="Tactical Agent"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
<q-card-section v-if="state.mode === 'mesh'">
|
||||
Fix issues with the Mesh Agent which handles take control, live terminal and file browser.
|
||||
Fix issues with the Mesh Agent which handles take control, live
|
||||
terminal and file browser.
|
||||
</q-card-section>
|
||||
<q-card-section v-else-if="state.mode === 'tacagent'">
|
||||
Fix issues with the Tactical RMM Agent service.
|
||||
</q-card-section>
|
||||
<q-card-actions align="right">
|
||||
<q-btn dense flat push label="Cancel" v-close-popup />
|
||||
<q-btn :loading="loading" dense flat push label="Recover" color="primary" type="submit" />
|
||||
<q-btn
|
||||
:loading="loading"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
label="Recover"
|
||||
color="primary"
|
||||
type="submit"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-form>
|
||||
</q-card>
|
||||
@@ -57,7 +71,10 @@ export default {
|
||||
async function sendRecovery() {
|
||||
loading.value = true;
|
||||
try {
|
||||
const result = await sendAgentRecovery(props.agent.agent_id, state.value);
|
||||
const result = await sendAgentRecovery(
|
||||
props.agent.agent_id,
|
||||
state.value
|
||||
);
|
||||
notifySuccess(result);
|
||||
onDialogOK();
|
||||
} catch (e) {
|
||||
|
@@ -24,7 +24,7 @@
|
||||
<q-card-section>
|
||||
<tactical-dropdown
|
||||
v-if="state.target === 'client'"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
v-model="state.client"
|
||||
:options="clientOptions"
|
||||
label="Select Client"
|
||||
@@ -34,7 +34,7 @@
|
||||
/>
|
||||
<tactical-dropdown
|
||||
v-else-if="state.target === 'site'"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
v-model="state.site"
|
||||
:options="siteOptions"
|
||||
label="Select Site"
|
||||
@@ -44,7 +44,7 @@
|
||||
/>
|
||||
<tactical-dropdown
|
||||
v-else-if="state.target === 'agents'"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
v-model="state.agents"
|
||||
:options="agentOptions"
|
||||
label="Select Agents"
|
||||
@@ -81,7 +81,7 @@
|
||||
|
||||
<q-card-section v-if="mode === 'script'" class="q-pt-none">
|
||||
<tactical-dropdown
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
v-model="state.script"
|
||||
:options="filteredScriptOptions"
|
||||
label="Select Script"
|
||||
@@ -122,7 +122,7 @@
|
||||
label="Custom shell"
|
||||
stack-label
|
||||
placeholder="/usr/bin/python3"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section v-if="mode === 'command'">
|
||||
@@ -132,7 +132,7 @@
|
||||
label="Command"
|
||||
stack-label
|
||||
:placeholder="cmdPlaceholder(state.shell)"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
/>
|
||||
</q-card-section>
|
||||
|
||||
@@ -145,7 +145,10 @@
|
||||
style="max-width: 150px"
|
||||
label="Timeout (seconds)"
|
||||
stack-label
|
||||
:rules="[val => !!val || '*Required', val => val >= 5 || 'Minimum is 5 seconds']"
|
||||
:rules="[
|
||||
(val) => !!val || '*Required',
|
||||
(val) => val >= 5 || 'Minimum is 5 seconds',
|
||||
]"
|
||||
/>
|
||||
</q-card-section>
|
||||
|
||||
@@ -162,14 +165,26 @@
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section v-show="false">
|
||||
<q-checkbox v-model="state.offlineAgents" label="Offline Agents (Run on next checkin)">
|
||||
<q-tooltip>If the agent is offline, a pending action will be created to run on agent checkin</q-tooltip>
|
||||
<q-checkbox
|
||||
v-model="state.offlineAgents"
|
||||
label="Offline Agents (Run on next checkin)"
|
||||
>
|
||||
<q-tooltip
|
||||
>If the agent is offline, a pending action will be created to run
|
||||
on agent checkin</q-tooltip
|
||||
>
|
||||
</q-checkbox>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-actions align="right">
|
||||
<q-btn label="Cancel" v-close-popup />
|
||||
<q-btn label="Run" color="primary" type="submit" :disable="loading" :loading="loading" />
|
||||
<q-btn
|
||||
label="Run"
|
||||
color="primary"
|
||||
type="submit"
|
||||
:disable="loading"
|
||||
:loading="loading"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-form>
|
||||
</q-card>
|
||||
@@ -227,7 +242,9 @@ export default {
|
||||
setup(props) {
|
||||
// setup vuex store
|
||||
const store = useStore();
|
||||
const showCommunityScripts = computed(() => store.state.showCommunityScripts);
|
||||
const showCommunityScripts = computed(
|
||||
() => store.state.showCommunityScripts
|
||||
);
|
||||
|
||||
const shellOptions = computed(() => {
|
||||
if (state.value.osType === "windows") {
|
||||
@@ -244,8 +261,10 @@ export default {
|
||||
});
|
||||
|
||||
const filteredOsTypeOptions = computed(() => {
|
||||
if (props.mode === "command") return osTypeOptions.filter(i => i.value !== "all");
|
||||
else if (props.mode === "patch") return osTypeOptions.filter(i => i.value === "windows");
|
||||
if (props.mode === "command")
|
||||
return osTypeOptions.filter((i) => i.value !== "all");
|
||||
else if (props.mode === "patch")
|
||||
return osTypeOptions.filter((i) => i.value === "windows");
|
||||
return osTypeOptions;
|
||||
});
|
||||
|
||||
@@ -253,7 +272,13 @@ export default {
|
||||
const { dialogRef, onDialogHide } = useDialogPluginComponent();
|
||||
|
||||
// dropdown setup
|
||||
const { script, scriptOptions, defaultTimeout, defaultArgs, getScriptOptions } = useScriptDropdown();
|
||||
const {
|
||||
script,
|
||||
scriptOptions,
|
||||
defaultTimeout,
|
||||
defaultArgs,
|
||||
getScriptOptions,
|
||||
} = useScriptDropdown();
|
||||
const { agents, agentOptions, getAgentOptions } = useAgentDropdown();
|
||||
const { site, siteOptions, getSiteOptions } = useSiteDropdown();
|
||||
const { client, clientOptions, getClientOptions } = useClientDropdown();
|
||||
@@ -280,7 +305,7 @@ export default {
|
||||
|
||||
watch(
|
||||
() => state.value.target,
|
||||
(newValue, oldValue) => {
|
||||
() => {
|
||||
client.value = null;
|
||||
site.value = null;
|
||||
agents.value = [];
|
||||
@@ -289,7 +314,7 @@ export default {
|
||||
|
||||
watch(
|
||||
() => state.value.osType,
|
||||
(newValue, oldValue) => {
|
||||
(newValue) => {
|
||||
state.value.custom_shell = null;
|
||||
|
||||
if (newValue === "windows") {
|
||||
@@ -329,7 +354,7 @@ export default {
|
||||
|
||||
return removeExtraOptionCategories(
|
||||
scriptOptions.value.filter(
|
||||
script =>
|
||||
(script) =>
|
||||
script.category ||
|
||||
!script.supported_platforms ||
|
||||
script.supported_platforms.length === 0 ||
|
||||
|
@@ -18,7 +18,12 @@
|
||||
<q-btn icon="close" flat round dense v-close-popup />
|
||||
</q-card-section>
|
||||
<div class="scroll" style="height: 65vh; max-height: 65vh">
|
||||
<q-tab-panels v-model="tab" animated transition-prev="jump-up" transition-next="jump-up">
|
||||
<q-tab-panels
|
||||
v-model="tab"
|
||||
animated
|
||||
transition-prev="jump-up"
|
||||
transition-next="jump-up"
|
||||
>
|
||||
<!-- general -->
|
||||
<q-tab-panel name="general">
|
||||
<q-card-section class="row">
|
||||
@@ -48,12 +53,24 @@
|
||||
<q-card-section class="row">
|
||||
<div class="col-2">Description:</div>
|
||||
<div class="col-2"></div>
|
||||
<q-input outlined dense v-model="agent.description" class="col-8" />
|
||||
<q-input
|
||||
outlined
|
||||
dense
|
||||
v-model="agent.description"
|
||||
class="col-8"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section class="row">
|
||||
<div class="col-2">Timezone:</div>
|
||||
<div class="col-2"></div>
|
||||
<q-select outlined dense options-dense v-model="timezone" :options="allTimezones" class="col-8" />
|
||||
<q-select
|
||||
outlined
|
||||
dense
|
||||
options-dense
|
||||
v-model="timezone"
|
||||
:options="allTimezones"
|
||||
class="col-8"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section class="row">
|
||||
<div class="col-10">Run checks every:</div>
|
||||
@@ -65,16 +82,23 @@
|
||||
v-model.number="agent.check_interval"
|
||||
class="col-2"
|
||||
:rules="[
|
||||
val => !!val || '*Required',
|
||||
val => val >= 15 || 'Minimum is 15 seconds',
|
||||
val => val <= 86400 || 'Maximum is 86400 seconds',
|
||||
(val) => !!val || '*Required',
|
||||
(val) => val >= 15 || 'Minimum is 15 seconds',
|
||||
(val) => val <= 86400 || 'Maximum is 86400 seconds',
|
||||
]"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section class="row">
|
||||
<div class="col-10">
|
||||
<q-icon class="q-pr-sm" name="fas fa-signal" size="1.2em" color="warning" /> Mark an agent as
|
||||
<span class="text-weight-bold">offline</span> if it has not checked in after:
|
||||
<q-icon
|
||||
class="q-pr-sm"
|
||||
name="fas fa-signal"
|
||||
size="1.2em"
|
||||
color="warning"
|
||||
/>
|
||||
Mark an agent as
|
||||
<span class="text-weight-bold">offline</span> if it has
|
||||
not checked in after:
|
||||
</div>
|
||||
<q-input
|
||||
dense
|
||||
@@ -84,16 +108,23 @@
|
||||
v-model.number="agent.offline_time"
|
||||
class="col-2"
|
||||
:rules="[
|
||||
val => !!val || '*Required',
|
||||
val => val >= 2 || 'Minimum is 2 minutes',
|
||||
val => val < 9999999 || 'Maximum is 9999999 minutes',
|
||||
(val) => !!val || '*Required',
|
||||
(val) => val >= 2 || 'Minimum is 2 minutes',
|
||||
(val) => val < 9999999 || 'Maximum is 9999999 minutes',
|
||||
]"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section class="row">
|
||||
<div class="col-10">
|
||||
<q-icon class="q-pr-sm" name="fas fa-signal" size="1.2em" color="negative" /> Mark an agent as
|
||||
<span class="text-weight-bold">overdue</span> if it has not checked in after:
|
||||
<q-icon
|
||||
class="q-pr-sm"
|
||||
name="fas fa-signal"
|
||||
size="1.2em"
|
||||
color="negative"
|
||||
/>
|
||||
Mark an agent as
|
||||
<span class="text-weight-bold">overdue</span> if it has
|
||||
not checked in after:
|
||||
</div>
|
||||
<q-input
|
||||
dense
|
||||
@@ -103,26 +134,39 @@
|
||||
v-model.number="agent.overdue_time"
|
||||
class="col-2"
|
||||
:rules="[
|
||||
val => !!val || '*Required',
|
||||
val => val >= 3 || 'Minimum is 3 minutes',
|
||||
val => val < 9999999 || 'Maximum is 9999999 minutes',
|
||||
(val) => !!val || '*Required',
|
||||
(val) => val >= 3 || 'Minimum is 3 minutes',
|
||||
(val) => val < 9999999 || 'Maximum is 9999999 minutes',
|
||||
]"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section class="row">
|
||||
<q-checkbox v-model="agent.overdue_email_alert" label="Get overdue email alerts" />
|
||||
<q-checkbox v-model="agent.overdue_text_alert" label="Get overdue sms alerts" />
|
||||
<q-checkbox v-model="agent.overdue_dashboard_alert" label="Get overdue dashboard alerts" />
|
||||
<q-checkbox
|
||||
v-model="agent.overdue_email_alert"
|
||||
label="Get overdue email alerts"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="agent.overdue_text_alert"
|
||||
label="Get overdue sms alerts"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="agent.overdue_dashboard_alert"
|
||||
label="Get overdue dashboard alerts"
|
||||
/>
|
||||
</q-card-section>
|
||||
</q-tab-panel>
|
||||
|
||||
<!-- custom fields -->
|
||||
<q-tab-panel name="customfields">
|
||||
<div class="text-subtitle" v-if="customFields.length === 0">
|
||||
No agent custom fields found. Go to **Settings > Global Settings > Custom Settings**
|
||||
No agent custom fields found. Go to **Settings > Global
|
||||
Settings > Custom Settings**
|
||||
</div>
|
||||
<q-card-section v-for="field in customFields" :key="field.id">
|
||||
<CustomField v-model="custom_fields[field.name]" :field="field" />
|
||||
<CustomField
|
||||
v-model="custom_fields[field.name]"
|
||||
:field="field"
|
||||
/>
|
||||
</q-card-section>
|
||||
</q-tab-panel>
|
||||
|
||||
@@ -135,12 +179,17 @@
|
||||
<q-tab-panel name="policies">
|
||||
<div class="text-subtitle2">Policies</div>
|
||||
<q-list separator padding dense>
|
||||
<q-item v-for="(policy, key) in agent.applied_policies" :key="key">
|
||||
<q-item
|
||||
v-for="(policy, key) in agent.applied_policies"
|
||||
:key="key"
|
||||
>
|
||||
<q-item-section>
|
||||
<q-item-label overline>
|
||||
{{ capitalize(key).split("_").join(" ") }}
|
||||
</q-item-label>
|
||||
<q-item-label>{{ policy ? policy.name : "None" }}</q-item-label>
|
||||
<q-item-label>{{
|
||||
policy ? policy.name : "None"
|
||||
}}</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section side v-if="policy">
|
||||
<q-item-label>
|
||||
@@ -154,11 +203,17 @@
|
||||
<q-list dense padding>
|
||||
<q-item>
|
||||
<q-item-section>
|
||||
<q-item-label>{{ agent.alert_template ? agent.alert_template.name : "None" }}</q-item-label>
|
||||
<q-item-label>{{
|
||||
agent.alert_template
|
||||
? agent.alert_template.name
|
||||
: "None"
|
||||
}}</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section side v-if="agent.alert_template">
|
||||
<q-item-label>
|
||||
<i>{{ agent.alert_template.is_active ? "" : "disabled" }}</i>
|
||||
<i>{{
|
||||
agent.alert_template.is_active ? "" : "disabled"
|
||||
}}</i>
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
@@ -218,18 +273,39 @@
|
||||
<q-item>
|
||||
<q-item-section>
|
||||
<q-item-label overline>Run Time Frequency</q-item-label>
|
||||
<q-item-label>{{ capitalize(agent.effective_patch_policy.run_time_frequency) }}</q-item-label>
|
||||
<q-item-label>{{
|
||||
capitalize(
|
||||
agent.effective_patch_policy.run_time_frequency
|
||||
)
|
||||
}}</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section v-if="agent.effective_patch_policy.run_time_frequency === 'daily'">
|
||||
<q-item-section
|
||||
v-if="
|
||||
agent.effective_patch_policy.run_time_frequency ===
|
||||
'daily'
|
||||
"
|
||||
>
|
||||
<q-item-label>
|
||||
<b>week days:</b>
|
||||
{{ weekDaystoString(agent.effective_patch_policy.run_time_days) }} <b>at hour:</b>
|
||||
{{
|
||||
weekDaystoString(
|
||||
agent.effective_patch_policy.run_time_days
|
||||
)
|
||||
}}
|
||||
<b>at hour:</b>
|
||||
{{ agent.effective_patch_policy.run_time_hour }}
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section v-else-if="agent.effective_patch_policy.run_time_frequency === 'monthly'">
|
||||
<q-item-section
|
||||
v-else-if="
|
||||
agent.effective_patch_policy.run_time_frequency ===
|
||||
'monthly'
|
||||
"
|
||||
>
|
||||
<q-item-label>
|
||||
<b>Every month on day:</b> {{ agent.effective_patch_policy.run_time_day }} <b>at hour:</b>
|
||||
<b>Every month on day:</b>
|
||||
{{ agent.effective_patch_policy.run_time_day }}
|
||||
<b>at hour:</b>
|
||||
{{ agent.effective_patch_policy.run_time_hour }}
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
@@ -239,28 +315,46 @@
|
||||
</q-item>
|
||||
<q-item>
|
||||
<q-item-section>
|
||||
<q-item-label overline>Reboot after installation</q-item-label>
|
||||
<q-item-label overline
|
||||
>Reboot after installation</q-item-label
|
||||
>
|
||||
<q-item-label>{{
|
||||
agent.effective_patch_policy.reboot_after_install !== "inherit"
|
||||
? capitalize(agent.effective_patch_policy.reboot_after_install)
|
||||
agent.effective_patch_policy.reboot_after_install !==
|
||||
"inherit"
|
||||
? capitalize(
|
||||
agent.effective_patch_policy
|
||||
.reboot_after_install
|
||||
)
|
||||
: "Do Nothing"
|
||||
}}</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item>
|
||||
<q-item-section>
|
||||
<q-item-label overline>Failed patch options</q-item-label>
|
||||
<q-item-label v-if="agent.effective_patch_policy.reprocess_failed_inherit"
|
||||
<q-item-label overline
|
||||
>Failed patch options</q-item-label
|
||||
>
|
||||
<q-item-label
|
||||
v-if="
|
||||
agent.effective_patch_policy
|
||||
.reprocess_failed_inherit
|
||||
"
|
||||
>Do Nothing</q-item-label
|
||||
>
|
||||
<q-item-label v-else>
|
||||
<b>Reprocess failed patches:</b>
|
||||
{{
|
||||
agent.effective_patch_policy.reprocess_failed
|
||||
? agent.effective_patch_policy.reprocess_failed_times
|
||||
? agent.effective_patch_policy
|
||||
.reprocess_failed_times
|
||||
: "Never"
|
||||
}}
|
||||
<b>Email on fail:</b>
|
||||
{{
|
||||
agent.effective_patch_policy.email_if_fail
|
||||
? "Yes"
|
||||
: "Never"
|
||||
}}
|
||||
<b>Email on fail:</b> {{ agent.effective_patch_policy.email_if_fail ? "Yes" : "Never" }}
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
@@ -294,7 +388,7 @@ export default {
|
||||
props: {
|
||||
agent_id: !String,
|
||||
},
|
||||
setup(props) {
|
||||
setup() {
|
||||
// quasar dialog setup
|
||||
const { dialogRef, onDialogHide } = useDialogPluginComponent();
|
||||
|
||||
@@ -325,9 +419,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
getAgentInfo() {
|
||||
this.$axios
|
||||
.get(`/agents/${this.agent_id}/`)
|
||||
.then(r => {
|
||||
this.$axios.get(`/agents/${this.agent_id}/`).then((r) => {
|
||||
this.agent = r.data;
|
||||
this.allTimezones = Object.freeze(r.data.all_timezones);
|
||||
|
||||
@@ -345,7 +437,9 @@ export default {
|
||||
}
|
||||
|
||||
for (let field of this.customFields) {
|
||||
const value = r.data.custom_fields.find(value => value.field === field.id);
|
||||
const value = r.data.custom_fields.find(
|
||||
(value) => value.field === field.id
|
||||
);
|
||||
|
||||
if (field.type === "multiple") {
|
||||
if (value) this.custom_fields[field.name] = value.value;
|
||||
@@ -358,19 +452,17 @@ export default {
|
||||
else this.custom_fields[field.name] = "";
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(e => {});
|
||||
});
|
||||
},
|
||||
getSiteOptions() {
|
||||
this.$axios
|
||||
.get("/clients/")
|
||||
.then(r => {
|
||||
r.data.forEach(client => {
|
||||
this.$axios.get("/clients/").then((r) => {
|
||||
r.data.forEach((client) => {
|
||||
this.siteOptions.push({ category: client.name });
|
||||
client.sites.forEach(site => this.siteOptions.push({ label: site.name, value: site.id }));
|
||||
client.sites.forEach((site) =>
|
||||
this.siteOptions.push({ label: site.name, value: site.id })
|
||||
);
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(e => {});
|
||||
},
|
||||
editAgent() {
|
||||
delete this.agent.all_timezones;
|
||||
@@ -386,14 +478,16 @@ export default {
|
||||
this.$axios
|
||||
.put(`/agents/${this.agent_id}/`, {
|
||||
...this.agent,
|
||||
custom_fields: this.formatCustomFields(this.customFields, this.custom_fields),
|
||||
custom_fields: this.formatCustomFields(
|
||||
this.customFields,
|
||||
this.custom_fields
|
||||
),
|
||||
})
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.$refs.dialogRef.hide();
|
||||
this.$emit("ok");
|
||||
this.notifySuccess("Agent was edited!");
|
||||
})
|
||||
.catch(e => {});
|
||||
});
|
||||
},
|
||||
weekDaystoString(array) {
|
||||
if (array.length === 0) return "not set";
|
||||
@@ -414,8 +508,8 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
// Get custom fields
|
||||
this.getCustomFields("agent").then(r => {
|
||||
this.customFields = r.data.filter(field => !field.hide_in_ui);
|
||||
this.getCustomFields("agent").then((r) => {
|
||||
this.customFields = r.data.filter((field) => !field.hide_in_ui);
|
||||
});
|
||||
this.getAgentInfo();
|
||||
this.getSiteOptions();
|
||||
|
@@ -23,7 +23,14 @@
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section class="q-gutter-sm">
|
||||
<q-select dense options-dense outlined label="Site" v-model="site" :options="sites" />
|
||||
<q-select
|
||||
dense
|
||||
options-dense
|
||||
outlined
|
||||
label="Site"
|
||||
v-model="site"
|
||||
:options="sites"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<div class="q-gutter-sm">
|
||||
@@ -49,8 +56,17 @@
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<div class="q-gutter-sm">
|
||||
<q-radio v-model="agenttype" val="server" label="Server" @update:model-value="power = false" />
|
||||
<q-radio v-model="agenttype" val="workstation" label="Workstation" />
|
||||
<q-radio
|
||||
v-model="agenttype"
|
||||
val="server"
|
||||
label="Server"
|
||||
@update:model-value="power = false"
|
||||
/>
|
||||
<q-radio
|
||||
v-model="agenttype"
|
||||
val="workstation"
|
||||
label="Workstation"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
@@ -70,20 +86,57 @@
|
||||
<div class="q-gutter-sm">
|
||||
<q-checkbox v-model="rdp" dense label="Enable RDP" />
|
||||
<q-checkbox v-model="ping" dense label="Enable Ping">
|
||||
<q-tooltip> Enable ICMP echo requests in the local firewall </q-tooltip>
|
||||
<q-tooltip>
|
||||
Enable ICMP echo requests in the local firewall
|
||||
</q-tooltip>
|
||||
</q-checkbox>
|
||||
<q-checkbox v-model="power" dense v-show="agenttype === 'workstation'" label="Disable sleep/hibernate" />
|
||||
<q-checkbox
|
||||
v-model="power"
|
||||
dense
|
||||
v-show="agenttype === 'workstation'"
|
||||
label="Disable sleep/hibernate"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
Arch
|
||||
<div class="q-gutter-sm">
|
||||
<q-radio v-model="arch" val="64" label="64 bit" v-show="agentOS === 'windows'" />
|
||||
<q-radio v-model="arch" val="32" label="32 bit" v-show="agentOS === 'windows'" />
|
||||
<q-radio v-model="arch" val="amd64" label="64 bit" v-show="agentOS !== 'windows'" />
|
||||
<q-radio v-model="arch" val="386" label="32 bit" v-show="agentOS !== 'windows'" />
|
||||
<q-radio v-model="arch" val="arm64" label="ARM 64 bit" v-show="agentOS !== 'windows'" />
|
||||
<q-radio v-model="arch" val="arm" label="ARM 32 bit (Rasp Pi)" v-show="agentOS !== 'windows'" />
|
||||
<q-radio
|
||||
v-model="arch"
|
||||
val="64"
|
||||
label="64 bit"
|
||||
v-show="agentOS === 'windows'"
|
||||
/>
|
||||
<q-radio
|
||||
v-model="arch"
|
||||
val="32"
|
||||
label="32 bit"
|
||||
v-show="agentOS === 'windows'"
|
||||
/>
|
||||
<q-radio
|
||||
v-model="arch"
|
||||
val="amd64"
|
||||
label="64 bit"
|
||||
v-show="agentOS !== 'windows'"
|
||||
/>
|
||||
<q-radio
|
||||
v-model="arch"
|
||||
val="386"
|
||||
label="32 bit"
|
||||
v-show="agentOS !== 'windows'"
|
||||
/>
|
||||
<q-radio
|
||||
v-model="arch"
|
||||
val="arm64"
|
||||
label="ARM 64 bit"
|
||||
v-show="agentOS !== 'windows'"
|
||||
/>
|
||||
<q-radio
|
||||
v-model="arch"
|
||||
val="arm"
|
||||
label="ARM 32 bit (Rasp Pi)"
|
||||
v-show="agentOS !== 'windows'"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
@@ -95,8 +148,18 @@
|
||||
v-show="agentOS === 'windows'"
|
||||
label="Dynamically generated exe"
|
||||
/>
|
||||
<q-radio v-model="installMethod" val="powershell" v-show="agentOS === 'windows'" label="Powershell" />
|
||||
<q-radio v-model="installMethod" val="manual" v-show="agentOS === 'windows'" label="Manual" />
|
||||
<q-radio
|
||||
v-model="installMethod"
|
||||
val="powershell"
|
||||
v-show="agentOS === 'windows'"
|
||||
label="Powershell"
|
||||
/>
|
||||
<q-radio
|
||||
v-model="installMethod"
|
||||
val="manual"
|
||||
v-show="agentOS === 'windows'"
|
||||
label="Manual"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
<q-card-actions align="left">
|
||||
@@ -144,11 +207,11 @@ export default {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.get("/clients/")
|
||||
.then(r => {
|
||||
.then((r) => {
|
||||
this.client_options = this.formatClientOptions(r.data);
|
||||
if (this.sitepk !== undefined && this.sitepk !== null) {
|
||||
this.client_options.forEach(client => {
|
||||
let site = client.sites.find(site => site.id === this.sitepk);
|
||||
this.client_options.forEach((client) => {
|
||||
let site = client.sites.find((site) => site.id === this.sitepk);
|
||||
|
||||
if (site !== undefined) {
|
||||
this.client = client;
|
||||
@@ -197,25 +260,24 @@ export default {
|
||||
};
|
||||
|
||||
if (this.installMethod === "manual") {
|
||||
this.$axios
|
||||
.post("/agents/installer/", data)
|
||||
.then(r => {
|
||||
this.$axios.post("/agents/installer/", data).then((r) => {
|
||||
this.info = {
|
||||
expires: this.expires,
|
||||
data: r.data,
|
||||
arch: this.arch,
|
||||
};
|
||||
this.showAgentDownload = true;
|
||||
})
|
||||
.catch(e => {});
|
||||
});
|
||||
} else if (this.installMethod === "exe") {
|
||||
this.$q.loading.show({ message: "Generating executable..." });
|
||||
|
||||
this.$axios
|
||||
.post("/agents/installer/", data, { responseType: "blob" })
|
||||
.then(r => {
|
||||
.then((r) => {
|
||||
this.$q.loading.hide();
|
||||
const blob = new Blob([r.data], { type: "application/vnd.microsoft.portable-executable" });
|
||||
const blob = new Blob([r.data], {
|
||||
type: "application/vnd.microsoft.portable-executable",
|
||||
});
|
||||
let link = document.createElement("a");
|
||||
link.href = window.URL.createObjectURL(blob);
|
||||
link.download = fileName;
|
||||
@@ -225,7 +287,10 @@ export default {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
} else if (this.installMethod === "powershell" || this.installMethod === "linux") {
|
||||
} else if (
|
||||
this.installMethod === "powershell" ||
|
||||
this.installMethod === "linux"
|
||||
) {
|
||||
this.$q.loading.show();
|
||||
let ext = this.installMethod === "powershell" ? "ps1" : "sh";
|
||||
const scriptName = `rmm-${clientStripped}-${siteStripped}-${this.agenttype}.${ext}`;
|
||||
|
@@ -89,7 +89,10 @@
|
||||
map-options
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section class="row" v-if="winupdatepolicy.run_time_frequency === 'monthly'">
|
||||
<q-card-section
|
||||
class="row"
|
||||
v-if="winupdatepolicy.run_time_frequency === 'monthly'"
|
||||
>
|
||||
<div class="col-3">Day of month to run:</div>
|
||||
<div class="col-4"></div>
|
||||
<q-select
|
||||
@@ -103,7 +106,10 @@
|
||||
map-options
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section class="row" v-show="winupdatepolicy.run_time_frequency !== 'inherit'">
|
||||
<q-card-section
|
||||
class="row"
|
||||
v-show="winupdatepolicy.run_time_frequency !== 'inherit'"
|
||||
>
|
||||
<div class="col-3">Scheduled Time:</div>
|
||||
<div class="col-4"></div>
|
||||
<q-select
|
||||
@@ -121,13 +127,41 @@
|
||||
v-show="winupdatepolicy.run_time_frequency !== 'inherit'"
|
||||
>
|
||||
<div class="q-gutter-sm">
|
||||
<q-checkbox v-model="winupdatepolicy.run_time_days" :val="1" label="Monday" />
|
||||
<q-checkbox v-model="winupdatepolicy.run_time_days" :val="2" label="Tuesday" />
|
||||
<q-checkbox v-model="winupdatepolicy.run_time_days" :val="3" label="Wednesday" />
|
||||
<q-checkbox v-model="winupdatepolicy.run_time_days" :val="4" label="Thursday" />
|
||||
<q-checkbox v-model="winupdatepolicy.run_time_days" :val="5" label="Friday" />
|
||||
<q-checkbox v-model="winupdatepolicy.run_time_days" :val="6" label="Saturday" />
|
||||
<q-checkbox v-model="winupdatepolicy.run_time_days" :val="0" label="Sunday" />
|
||||
<q-checkbox
|
||||
v-model="winupdatepolicy.run_time_days"
|
||||
:val="1"
|
||||
label="Monday"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="winupdatepolicy.run_time_days"
|
||||
:val="2"
|
||||
label="Tuesday"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="winupdatepolicy.run_time_days"
|
||||
:val="3"
|
||||
label="Wednesday"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="winupdatepolicy.run_time_days"
|
||||
:val="4"
|
||||
label="Thursday"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="winupdatepolicy.run_time_days"
|
||||
:val="5"
|
||||
label="Friday"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="winupdatepolicy.run_time_days"
|
||||
:val="6"
|
||||
label="Saturday"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="winupdatepolicy.run_time_days"
|
||||
:val="0"
|
||||
label="Sunday"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
<!-- Reboot After Installation -->
|
||||
@@ -151,12 +185,21 @@
|
||||
<q-separator />
|
||||
<q-card-section class="row" v-if="!policy">
|
||||
<div class="col-5">
|
||||
<q-checkbox v-model="winupdatepolicy.reprocess_failed_inherit" label="Inherit failed patch settings" />
|
||||
<q-checkbox
|
||||
v-model="winupdatepolicy.reprocess_failed_inherit"
|
||||
label="Inherit failed patch settings"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
<q-card-section class="row" v-show="!winupdatepolicy.reprocess_failed_inherit">
|
||||
<q-card-section
|
||||
class="row"
|
||||
v-show="!winupdatepolicy.reprocess_failed_inherit"
|
||||
>
|
||||
<div class="col-5">
|
||||
<q-checkbox v-model="winupdatepolicy.reprocess_failed" label="Reprocess failed patches" />
|
||||
<q-checkbox
|
||||
v-model="winupdatepolicy.reprocess_failed"
|
||||
label="Reprocess failed patches"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-3">
|
||||
@@ -166,17 +209,25 @@
|
||||
type="number"
|
||||
filled
|
||||
label="Times"
|
||||
:rules="[val => val > 0 || 'Must be greater than 0']"
|
||||
:rules="[(val) => val > 0 || 'Must be greater than 0']"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-3"></div>
|
||||
<q-checkbox v-model="winupdatepolicy.email_if_fail" label="Send an email when patch installation fails" />
|
||||
<q-checkbox
|
||||
v-model="winupdatepolicy.email_if_fail"
|
||||
label="Send an email when patch installation fails"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-actions align="left" v-if="policy">
|
||||
<q-btn label="Submit" color="primary" @click="submit" />
|
||||
<q-btn label="Cancel" @click="$emit('hide')" />
|
||||
<q-space />
|
||||
<q-btn v-if="editing" label="Remove Policy" color="negative" @click="deletePolicy(winupdatepolicy)" />
|
||||
<q-btn
|
||||
v-if="editing"
|
||||
label="Remove Policy"
|
||||
color="negative"
|
||||
@click="deletePolicy(winupdatepolicy)"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</div>
|
||||
</template>
|
||||
@@ -240,25 +291,28 @@ export default {
|
||||
// editing patch policy
|
||||
if (this.editing) {
|
||||
this.$axios
|
||||
.put(`/automation/patchpolicy/${this.winupdatepolicy.id}/`, this.winupdatepolicy)
|
||||
.then(response => {
|
||||
.put(
|
||||
`/automation/patchpolicy/${this.winupdatepolicy.id}/`,
|
||||
this.winupdatepolicy
|
||||
)
|
||||
.then(() => {
|
||||
this.$q.loading.hide();
|
||||
this.$emit("close");
|
||||
this.notifySuccess("Patch policy was edited successfully!");
|
||||
})
|
||||
.catch(error => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
} else {
|
||||
// adding patch policy
|
||||
this.$axios
|
||||
.post("/automation/patchpolicy/", this.winupdatepolicy)
|
||||
.then(response => {
|
||||
.then(() => {
|
||||
this.$q.loading.hide();
|
||||
this.$emit("close");
|
||||
this.notifySuccess("Patch policy was created successfully!");
|
||||
})
|
||||
.catch(error => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
}
|
||||
@@ -275,12 +329,12 @@ export default {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.delete(`/automation/patchpolicy/${policy.id}/`)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.$q.loading.hide();
|
||||
this.$emit("close");
|
||||
this.notifySuccess("Patch policy was deleted successfully!");
|
||||
})
|
||||
.catch(error => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
});
|
||||
|
@@ -21,7 +21,15 @@
|
||||
</q-card-section>
|
||||
<q-card-actions align="right">
|
||||
<q-btn dense flat push label="Cancel" v-close-popup />
|
||||
<q-btn :loading="loading" dense flat push label="Schedule Reboot" color="primary" @click="scheduleReboot" />
|
||||
<q-btn
|
||||
:loading="loading"
|
||||
dense
|
||||
flat
|
||||
push
|
||||
label="Schedule Reboot"
|
||||
color="primary"
|
||||
@click="scheduleReboot"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
@@ -55,7 +63,7 @@ export default {
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const result = await scheduleAgentReboot(props.agent.agent_id, state.value);
|
||||
await scheduleAgentReboot(props.agent.agent_id, state.value);
|
||||
$q.dialog({
|
||||
title: "Reboot pending",
|
||||
style: "width: 40vw",
|
||||
|
@@ -1,14 +1,36 @@
|
||||
<template>
|
||||
<q-dialog ref="dialogRef" @hide="onDialogHide" persistent @keydown.esc="onDialogHide" :maximized="maximized">
|
||||
<q-dialog
|
||||
ref="dialogRef"
|
||||
@hide="onDialogHide"
|
||||
persistent
|
||||
@keydown.esc="onDialogHide"
|
||||
:maximized="maximized"
|
||||
>
|
||||
<q-card class="dialog-plugin" style="min-width: 60vw">
|
||||
<q-bar>
|
||||
Run a script on {{ agent.hostname }}
|
||||
<q-space />
|
||||
<q-btn dense flat icon="minimize" @click="maximized = false" :disable="!maximized">
|
||||
<q-tooltip v-if="maximized" class="bg-white text-primary">Minimize</q-tooltip>
|
||||
<q-btn
|
||||
dense
|
||||
flat
|
||||
icon="minimize"
|
||||
@click="maximized = false"
|
||||
:disable="!maximized"
|
||||
>
|
||||
<q-tooltip v-if="maximized" class="bg-white text-primary"
|
||||
>Minimize</q-tooltip
|
||||
>
|
||||
</q-btn>
|
||||
<q-btn dense flat icon="crop_square" @click="maximized = true" :disable="maximized">
|
||||
<q-tooltip v-if="!maximized" class="bg-white text-primary">Maximize</q-tooltip>
|
||||
<q-btn
|
||||
dense
|
||||
flat
|
||||
icon="crop_square"
|
||||
@click="maximized = true"
|
||||
:disable="maximized"
|
||||
>
|
||||
<q-tooltip v-if="!maximized" class="bg-white text-primary"
|
||||
>Maximize</q-tooltip
|
||||
>
|
||||
</q-btn>
|
||||
<q-btn dense flat icon="close" v-close-popup>
|
||||
<q-tooltip class="bg-white text-primary">Close</q-tooltip>
|
||||
@@ -17,7 +39,7 @@
|
||||
<q-form @submit.prevent="sendScript">
|
||||
<q-card-section>
|
||||
<tactical-dropdown
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
v-model="state.script"
|
||||
:options="filteredScriptOptions"
|
||||
label="Select script"
|
||||
@@ -26,8 +48,19 @@
|
||||
filterable
|
||||
>
|
||||
<template v-slot:after>
|
||||
<q-btn size="sm" round dense flat icon="info" @click="openScriptURL">
|
||||
<q-tooltip v-if="syntax" class="bg-white text-primary text-body1" v-html="formatScriptSyntax(syntax)" />
|
||||
<q-btn
|
||||
size="sm"
|
||||
round
|
||||
dense
|
||||
flat
|
||||
icon="info"
|
||||
@click="openScriptURL"
|
||||
>
|
||||
<q-tooltip
|
||||
v-if="syntax"
|
||||
class="bg-white text-primary text-body1"
|
||||
v-html="formatScriptSyntax(syntax)"
|
||||
/>
|
||||
</q-btn>
|
||||
</template>
|
||||
</tactical-dropdown>
|
||||
@@ -45,15 +78,33 @@
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
<q-option-group v-model="state.output" :options="outputOptions" color="primary" inline dense />
|
||||
<q-option-group
|
||||
v-model="state.output"
|
||||
:options="outputOptions"
|
||||
color="primary"
|
||||
inline
|
||||
dense
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section v-if="state.output === 'email'">
|
||||
<div class="q-gutter-sm">
|
||||
<q-radio dense v-model="state.emailMode" val="default" label="Use email addresses from global settings" />
|
||||
<q-radio dense v-model="state.emailMode" val="custom" label="Custom emails" />
|
||||
<q-radio
|
||||
dense
|
||||
v-model="state.emailMode"
|
||||
val="default"
|
||||
label="Use email addresses from global settings"
|
||||
/>
|
||||
<q-radio
|
||||
dense
|
||||
v-model="state.emailMode"
|
||||
val="custom"
|
||||
label="Custom emails"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
<q-card-section v-if="state.emailMode === 'custom' && state.output === 'email'">
|
||||
<q-card-section
|
||||
v-if="state.emailMode === 'custom' && state.output === 'email'"
|
||||
>
|
||||
<tactical-dropdown
|
||||
v-model="state.emails"
|
||||
label="Email recipients (press Enter after typing each email)"
|
||||
@@ -67,7 +118,7 @@
|
||||
</q-card-section>
|
||||
<q-card-section v-if="state.output === 'collector'">
|
||||
<tactical-dropdown
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
outlined
|
||||
v-model="state.custom_field"
|
||||
:options="customFieldOptions"
|
||||
@@ -86,14 +137,27 @@
|
||||
style="max-width: 150px"
|
||||
label="Timeout (seconds)"
|
||||
stack-label
|
||||
:rules="[val => !!val || '*Required', val => val >= 5 || 'Minimum is 5 seconds']"
|
||||
:rules="[
|
||||
(val) => !!val || '*Required',
|
||||
(val) => val >= 5 || 'Minimum is 5 seconds',
|
||||
]"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-actions align="right">
|
||||
<q-btn label="Cancel" v-close-popup />
|
||||
<q-btn :loading="loading" :disabled="loading" label="Run" color="primary" type="submit" />
|
||||
<q-btn
|
||||
:loading="loading"
|
||||
:disabled="loading"
|
||||
label="Run"
|
||||
color="primary"
|
||||
type="submit"
|
||||
/>
|
||||
</q-card-actions>
|
||||
<q-card-section v-if="ret !== null" class="q-pl-md q-pr-md q-pt-none q-ma-none scroll" style="max-height: 50vh">
|
||||
<q-card-section
|
||||
v-if="ret !== null"
|
||||
class="q-pl-md q-pr-md q-pt-none q-ma-none scroll"
|
||||
style="max-height: 50vh"
|
||||
>
|
||||
<pre>{{ ret }}</pre>
|
||||
</q-card-section>
|
||||
</q-form>
|
||||
@@ -109,7 +173,10 @@ import { useScriptDropdown } from "@/composables/scripts";
|
||||
import { useCustomFieldDropdown } from "@/composables/core";
|
||||
import { runScript } from "@/api/agents";
|
||||
import { notifySuccess } from "@/utils/notify";
|
||||
import { formatScriptSyntax, removeExtraOptionCategories } from "@/utils/format";
|
||||
import {
|
||||
formatScriptSyntax,
|
||||
removeExtraOptionCategories,
|
||||
} from "@/utils/format";
|
||||
|
||||
//ui imports
|
||||
import TacticalDropdown from "@/components/ui/TacticalDropdown";
|
||||
@@ -136,7 +203,8 @@ export default {
|
||||
const { dialogRef, onDialogHide } = useDialogPluginComponent();
|
||||
|
||||
// setup dropdowns
|
||||
const { script, scriptOptions, defaultTimeout, defaultArgs, syntax, link } = useScriptDropdown(props.script, {
|
||||
const { script, scriptOptions, defaultTimeout, defaultArgs, syntax, link } =
|
||||
useScriptDropdown(props.script, {
|
||||
onMount: true,
|
||||
filterByPlatform: props.agent.plat,
|
||||
});
|
||||
@@ -177,7 +245,7 @@ export default {
|
||||
const filteredScriptOptions = computed(() => {
|
||||
return removeExtraOptionCategories(
|
||||
scriptOptions.value.filter(
|
||||
script =>
|
||||
(script) =>
|
||||
script.category ||
|
||||
!script.supported_platforms ||
|
||||
script.supported_platforms.length === 0 ||
|
||||
@@ -187,7 +255,10 @@ export default {
|
||||
});
|
||||
|
||||
// watchers
|
||||
watch([() => state.value.output, () => state.value.emailMode], () => (state.value.emails = []));
|
||||
watch(
|
||||
[() => state.value.output, () => state.value.emailMode],
|
||||
() => (state.value.emails = [])
|
||||
);
|
||||
|
||||
return {
|
||||
// reactive data
|
||||
|
@@ -1,6 +1,14 @@
|
||||
<template>
|
||||
<q-dialog ref="dialogRef" @hide="onDialogHide" persistent @keydown.esc="onDialogHide">
|
||||
<q-card class="q-dialog-plugin" :style="{ 'min-width': !ret ? '40vw' : '70vw' }">
|
||||
<q-dialog
|
||||
ref="dialogRef"
|
||||
@hide="onDialogHide"
|
||||
persistent
|
||||
@keydown.esc="onDialogHide"
|
||||
>
|
||||
<q-card
|
||||
class="q-dialog-plugin"
|
||||
:style="{ 'min-width': !ret ? '40vw' : '70vw' }"
|
||||
>
|
||||
<q-bar>
|
||||
Send command on {{ agent.hostname }}
|
||||
<q-space />
|
||||
@@ -20,9 +28,27 @@
|
||||
label="Bash"
|
||||
@update:model-value="state.custom_shell = null"
|
||||
/>
|
||||
<q-radio v-if="agent.plat !== 'windows'" dense v-model="state.shell" val="custom" label="Custom" />
|
||||
<q-radio v-if="agent.plat === 'windows'" dense v-model="state.shell" val="cmd" label="CMD" />
|
||||
<q-radio v-if="agent.plat === 'windows'" dense v-model="state.shell" val="powershell" label="Powershell" />
|
||||
<q-radio
|
||||
v-if="agent.plat !== 'windows'"
|
||||
dense
|
||||
v-model="state.shell"
|
||||
val="custom"
|
||||
label="Custom"
|
||||
/>
|
||||
<q-radio
|
||||
v-if="agent.plat === 'windows'"
|
||||
dense
|
||||
v-model="state.shell"
|
||||
val="cmd"
|
||||
label="CMD"
|
||||
/>
|
||||
<q-radio
|
||||
v-if="agent.plat === 'windows'"
|
||||
dense
|
||||
v-model="state.shell"
|
||||
val="powershell"
|
||||
label="Powershell"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
<q-card-section v-if="state.shell === 'custom'">
|
||||
@@ -32,7 +58,7 @@
|
||||
label="Custom shell"
|
||||
stack-label
|
||||
placeholder="/usr/bin/python3"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section>
|
||||
@@ -45,9 +71,9 @@
|
||||
label="Timeout (seconds)"
|
||||
stack-label
|
||||
:rules="[
|
||||
val => !!val || '*Required',
|
||||
val => val >= 10 || 'Minimum is 10 seconds',
|
||||
val => val <= 3600 || 'Maximum is 3600 seconds',
|
||||
(val) => !!val || '*Required',
|
||||
(val) => val >= 10 || 'Minimum is 10 seconds',
|
||||
(val) => val <= 3600 || 'Maximum is 3600 seconds',
|
||||
]"
|
||||
/>
|
||||
</q-card-section>
|
||||
@@ -58,14 +84,26 @@
|
||||
label="Command"
|
||||
stack-label
|
||||
:placeholder="cmdPlaceholder(state.shell)"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-actions align="right">
|
||||
<q-btn flat dense push label="Cancel" v-close-popup />
|
||||
<q-btn :loading="loading" flat dense push label="Send" color="primary" type="submit" />
|
||||
<q-btn
|
||||
:loading="loading"
|
||||
flat
|
||||
dense
|
||||
push
|
||||
label="Send"
|
||||
color="primary"
|
||||
type="submit"
|
||||
/>
|
||||
</q-card-actions>
|
||||
<q-card-section v-if="ret !== null" class="q-pl-md q-pr-md q-pt-none q-ma-none scroll" style="max-height: 50vh">
|
||||
<q-card-section
|
||||
v-if="ret !== null"
|
||||
class="q-pl-md q-pr-md q-pt-none q-ma-none scroll"
|
||||
style="max-height: 50vh"
|
||||
>
|
||||
<pre>{{ ret }}</pre>
|
||||
</q-card-section>
|
||||
</q-form>
|
||||
|
@@ -16,14 +16,32 @@
|
||||
</q-banner>
|
||||
<q-card-section>
|
||||
Select Version
|
||||
<q-select square disable dense options-dense outlined v-model="version" :options="versions" />
|
||||
<q-select
|
||||
square
|
||||
disable
|
||||
dense
|
||||
options-dense
|
||||
outlined
|
||||
v-model="version"
|
||||
:options="versions"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section v-show="version !== null">
|
||||
Select Agent
|
||||
<br />
|
||||
<q-separator />
|
||||
<q-checkbox v-model="selectAll" label="Select All" @update:model-value="selectAllAction" />
|
||||
<q-btn v-show="group.length !== 0" label="Update" color="primary" @click="update" class="q-ml-xl" />
|
||||
<q-checkbox
|
||||
v-model="selectAll"
|
||||
label="Select All"
|
||||
@update:model-value="selectAllAction"
|
||||
/>
|
||||
<q-btn
|
||||
v-show="group.length !== 0"
|
||||
label="Update"
|
||||
color="primary"
|
||||
@click="update"
|
||||
class="q-ml-xl"
|
||||
/>
|
||||
<q-separator />
|
||||
<q-option-group
|
||||
v-model="group"
|
||||
@@ -60,7 +78,7 @@ export default {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.get("/agents/versions/")
|
||||
.then(r => {
|
||||
.then((r) => {
|
||||
this.versions = r.data.versions;
|
||||
this.version = r.data.versions[0];
|
||||
this.agents = r.data.agents;
|
||||
@@ -72,18 +90,15 @@ export default {
|
||||
},
|
||||
update() {
|
||||
const data = { agent_ids: this.group };
|
||||
this.$axios
|
||||
.post("/agents/update/", data)
|
||||
.then(r => {
|
||||
this.$axios.post("/agents/update/", data).then(() => {
|
||||
this.$emit("close");
|
||||
this.notifySuccess("Agents will now be updated");
|
||||
})
|
||||
.catch(e => {});
|
||||
});
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
agentIds() {
|
||||
return this.agents.map(k => k.agent_id);
|
||||
return this.agents.map((k) => k.agent_id);
|
||||
},
|
||||
agentOptions() {
|
||||
const options = [];
|
||||
|
@@ -47,8 +47,14 @@
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section>
|
||||
<q-checkbox v-model="localTemplate.exclude_workstations" label="Exclude Workstations" />
|
||||
<q-checkbox v-model="localTemplate.exclude_servers" label="Exclude Servers" />
|
||||
<q-checkbox
|
||||
v-model="localTemplate.exclude_workstations"
|
||||
label="Exclude Workstations"
|
||||
/>
|
||||
<q-checkbox
|
||||
v-model="localTemplate.exclude_servers"
|
||||
label="Exclude Servers"
|
||||
/>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-actions align="right">
|
||||
@@ -90,12 +96,12 @@ export default {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.put(`alerts/templates/${this.template.id}/`, this.localTemplate)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.$q.loading.hide();
|
||||
this.onOk();
|
||||
this.notifySuccess("Alert Template exclusions added");
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
@@ -103,12 +109,17 @@ export default {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.get("/clients/")
|
||||
.then(r => {
|
||||
this.clientOptions = r.data.map(client => ({ label: client.name, value: client.id }));
|
||||
.then((r) => {
|
||||
this.clientOptions = r.data.map((client) => ({
|
||||
label: client.name,
|
||||
value: client.id,
|
||||
}));
|
||||
|
||||
r.data.forEach(client => {
|
||||
r.data.forEach((client) => {
|
||||
this.siteOptions.push({ category: client.name });
|
||||
client.sites.forEach(site => this.siteOptions.push({ label: site.name, value: site.id }));
|
||||
client.sites.forEach((site) =>
|
||||
this.siteOptions.push({ label: site.name, value: site.id })
|
||||
);
|
||||
});
|
||||
this.$q.loading.hide();
|
||||
})
|
||||
@@ -117,7 +128,9 @@ export default {
|
||||
});
|
||||
},
|
||||
getOptions() {
|
||||
this.getAgentOptions("id").then(options => (this.agentOptions = Object.freeze(options)));
|
||||
this.getAgentOptions("id").then(
|
||||
(options) => (this.agentOptions = Object.freeze(options))
|
||||
);
|
||||
this.getClientsandSites();
|
||||
},
|
||||
show() {
|
||||
@@ -141,7 +154,8 @@ export default {
|
||||
this.localTemplate.excluded_sites = this.template.excluded_sites;
|
||||
this.localTemplate.excluded_agents = this.template.excluded_agents;
|
||||
this.localTemplate.exclude_servers = this.template.exclude_servers;
|
||||
this.localTemplate.exclude_workstations = this.template.exclude_workstations;
|
||||
this.localTemplate.exclude_workstations =
|
||||
this.template.exclude_workstations;
|
||||
this.getOptions();
|
||||
},
|
||||
};
|
||||
|
@@ -22,10 +22,18 @@
|
||||
>
|
||||
</q-select>
|
||||
</q-card-section>
|
||||
<q-card-section v-else> No Alert Templates have been setup. Go to Settings > Alerts Manager </q-card-section>
|
||||
<q-card-section v-else>
|
||||
No Alert Templates have been setup. Go to Settings > Alerts Manager
|
||||
</q-card-section>
|
||||
<q-card-actions align="right">
|
||||
<q-btn dense flat label="Cancel" v-close-popup />
|
||||
<q-btn v-if="options.length > 0" flat label="Submit" color="primary" type="submit" />
|
||||
<q-btn
|
||||
v-if="options.length > 0"
|
||||
flat
|
||||
label="Submit"
|
||||
color="primary"
|
||||
type="submit"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-form>
|
||||
</q-card>
|
||||
@@ -86,12 +94,12 @@ export default {
|
||||
const text = this.selectedTemplate ? "assigned" : "removed";
|
||||
this.$axios
|
||||
.put(url, data)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.$q.loading.hide();
|
||||
this.onOk();
|
||||
this.notifySuccess(`Alert Template ${text} successfully!`);
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
@@ -99,14 +107,14 @@ export default {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.get("/alerts/templates/")
|
||||
.then(r => {
|
||||
this.options = r.data.map(template => ({
|
||||
.then((r) => {
|
||||
this.options = r.data.map((template) => ({
|
||||
label: template.name,
|
||||
value: template.id,
|
||||
}));
|
||||
this.$q.loading.hide();
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
|
@@ -8,8 +8,20 @@
|
||||
<q-tooltip class="bg-white text-primary">Close</q-tooltip>
|
||||
</q-btn>
|
||||
</q-bar>
|
||||
<q-stepper v-model="step" ref="stepper" alternative-labels header-nav color="primary" animated>
|
||||
<q-step :name="1" :error="!template.name && step > 1" title="General Settings" icon="settings">
|
||||
<q-stepper
|
||||
v-model="step"
|
||||
ref="stepper"
|
||||
alternative-labels
|
||||
header-nav
|
||||
color="primary"
|
||||
animated
|
||||
>
|
||||
<q-step
|
||||
:name="1"
|
||||
:error="!template.name && step > 1"
|
||||
title="General Settings"
|
||||
icon="settings"
|
||||
>
|
||||
<q-card flat>
|
||||
<q-card-section>
|
||||
<q-input
|
||||
@@ -18,30 +30,52 @@
|
||||
outlined
|
||||
dense
|
||||
v-model="template.name"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
/>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section>
|
||||
<q-toggle v-model="template.is_active" color="green" label="Enabled" left-label />
|
||||
<q-toggle
|
||||
v-model="template.is_active"
|
||||
color="green"
|
||||
label="Enabled"
|
||||
left-label
|
||||
/>
|
||||
</q-card-section>
|
||||
|
||||
<div class="q-pl-md text-subtitle1">Email Settings (Overrides global email settings)</div>
|
||||
<div class="q-pl-md text-subtitle1">
|
||||
Email Settings (Overrides global email settings)
|
||||
</div>
|
||||
|
||||
<q-card-section>
|
||||
<q-input label="Email From address" class="q-mb-sm" outlined dense v-model="template.email_from" />
|
||||
<q-input
|
||||
label="Email From address"
|
||||
class="q-mb-sm"
|
||||
outlined
|
||||
dense
|
||||
v-model="template.email_from"
|
||||
/>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section class="row">
|
||||
<div class="col-2 q-mb-sm">Email recipients</div>
|
||||
<div class="col-4 q-mb-sm">
|
||||
<q-list dense v-if="template.email_recipients.length !== 0">
|
||||
<q-item v-for="email in template.email_recipients" :key="email" dense>
|
||||
<q-item
|
||||
v-for="email in template.email_recipients"
|
||||
:key="email"
|
||||
dense
|
||||
>
|
||||
<q-item-section>
|
||||
<q-item-label>{{ email }}</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section side>
|
||||
<q-icon class="cursor-pointer" name="delete" color="red" @click="removeEmail(email)" />
|
||||
<q-icon
|
||||
class="cursor-pointer"
|
||||
name="delete"
|
||||
color="red"
|
||||
@click="removeEmail(email)"
|
||||
/>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
@@ -53,22 +87,39 @@
|
||||
</div>
|
||||
<div class="col-3 q-mb-sm"></div>
|
||||
<div class="col-3 q-mb-sm">
|
||||
<q-btn size="sm" icon="fas fa-plus" color="secondary" label="Add email" @click="toggleAddEmail" />
|
||||
<q-btn
|
||||
size="sm"
|
||||
icon="fas fa-plus"
|
||||
color="secondary"
|
||||
label="Add email"
|
||||
@click="toggleAddEmail"
|
||||
/>
|
||||
</div>
|
||||
</q-card-section>
|
||||
|
||||
<div class="q-pl-md text-subtitle1">SMS Settings (Overrides global SMS settings)</div>
|
||||
<div class="q-pl-md text-subtitle1">
|
||||
SMS Settings (Overrides global SMS settings)
|
||||
</div>
|
||||
|
||||
<q-card-section class="row">
|
||||
<div class="col-2 q-mb-sm">SMS recipients</div>
|
||||
<div class="col-4 q-mb-md">
|
||||
<q-list dense v-if="template.text_recipients.length !== 0">
|
||||
<q-item v-for="num in template.text_recipients" :key="num" dense>
|
||||
<q-item
|
||||
v-for="num in template.text_recipients"
|
||||
:key="num"
|
||||
dense
|
||||
>
|
||||
<q-item-section>
|
||||
<q-item-label>{{ num }}</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section side>
|
||||
<q-icon class="cursor-pointer" name="delete" color="red" @click="removeSMSNumber(num)" />
|
||||
<q-icon
|
||||
class="cursor-pointer"
|
||||
name="delete"
|
||||
color="red"
|
||||
@click="removeSMSNumber(num)"
|
||||
/>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
@@ -99,7 +150,8 @@
|
||||
<span style="text-decoration: underline; cursor: help"
|
||||
>Alert Failure Settings
|
||||
<q-tooltip>
|
||||
The selected script will run when an alert is triggered. This script will run on any online agent.
|
||||
The selected script will run when an alert is triggered. This
|
||||
script will run on any online agent.
|
||||
</q-tooltip>
|
||||
</span>
|
||||
</div>
|
||||
@@ -119,14 +171,22 @@
|
||||
@update:model-value="setScriptDefaults('failure')"
|
||||
>
|
||||
<template v-slot:option="scope">
|
||||
<q-item v-if="!scope.opt.category" v-bind="scope.itemProps" class="q-pl-lg">
|
||||
<q-item
|
||||
v-if="!scope.opt.category"
|
||||
v-bind="scope.itemProps"
|
||||
class="q-pl-lg"
|
||||
>
|
||||
<q-item-section>
|
||||
<q-item-label v-html="scope.opt.label"></q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item-label v-if="scope.opt.category" v-bind="scope.itemProps" header class="q-pa-sm">{{
|
||||
scope.opt.category
|
||||
}}</q-item-label>
|
||||
<q-item-label
|
||||
v-if="scope.opt.category"
|
||||
v-bind="scope.itemProps"
|
||||
header
|
||||
class="q-pa-sm"
|
||||
>{{ scope.opt.category }}</q-item-label
|
||||
>
|
||||
</template>
|
||||
</q-select>
|
||||
|
||||
@@ -152,9 +212,9 @@
|
||||
v-model.number="template.action_timeout"
|
||||
dense
|
||||
:rules="[
|
||||
val => !!val || 'Failure action timeout is required',
|
||||
val => val > 0 || 'Timeout must be greater than 0',
|
||||
val => val <= 60 || 'Timeout must be 60 or less',
|
||||
(val) => !!val || 'Failure action timeout is required',
|
||||
(val) => val > 0 || 'Timeout must be greater than 0',
|
||||
(val) => val <= 60 || 'Timeout must be 60 or less',
|
||||
]"
|
||||
/>
|
||||
</q-card-section>
|
||||
@@ -163,7 +223,8 @@
|
||||
<span style="text-decoration: underline; cursor: help"
|
||||
>Alert Resolved Settings
|
||||
<q-tooltip>
|
||||
The selected script will run when an alert is resolved. This script will run on any online agent.
|
||||
The selected script will run when an alert is resolved. This
|
||||
script will run on any online agent.
|
||||
</q-tooltip>
|
||||
</span>
|
||||
</div>
|
||||
@@ -183,14 +244,22 @@
|
||||
@update:model-value="setScriptDefaults('resolved')"
|
||||
>
|
||||
<template v-slot:option="scope">
|
||||
<q-item v-if="!scope.opt.category" v-bind="scope.itemProps" class="q-pl-lg">
|
||||
<q-item
|
||||
v-if="!scope.opt.category"
|
||||
v-bind="scope.itemProps"
|
||||
class="q-pl-lg"
|
||||
>
|
||||
<q-item-section>
|
||||
<q-item-label v-html="scope.opt.label"></q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item-label v-if="scope.opt.category" v-bind="scope.itemProps" header class="q-pa-sm">{{
|
||||
scope.opt.category
|
||||
}}</q-item-label>
|
||||
<q-item-label
|
||||
v-if="scope.opt.category"
|
||||
v-bind="scope.itemProps"
|
||||
header
|
||||
class="q-pa-sm"
|
||||
>{{ scope.opt.category }}</q-item-label
|
||||
>
|
||||
</template>
|
||||
</q-select>
|
||||
|
||||
@@ -216,9 +285,9 @@
|
||||
v-model.number="template.resolved_action_timeout"
|
||||
dense
|
||||
:rules="[
|
||||
val => !!val || 'Resolved action timeout is required',
|
||||
val => val > 0 || 'Timeout must be greater than 0',
|
||||
val => val <= 60 || 'Timeout must be 60 or less',
|
||||
(val) => !!val || 'Resolved action timeout is required',
|
||||
(val) => val > 0 || 'Timeout must be greater than 0',
|
||||
(val) => val <= 60 || 'Timeout must be 60 or less',
|
||||
]"
|
||||
/>
|
||||
</q-card-section>
|
||||
@@ -226,16 +295,34 @@
|
||||
<div class="q-pl-md text-subtitle1">
|
||||
<span style="text-decoration: underline; cursor: help"
|
||||
>Run actions only on
|
||||
<q-tooltip> The selected script will only run on the following types of alerts </q-tooltip>
|
||||
<q-tooltip>
|
||||
The selected script will only run on the following types of
|
||||
alerts
|
||||
</q-tooltip>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<q-card-section>
|
||||
<q-toggle v-model="template.agent_script_actions" label="Agents" color="green" left-label />
|
||||
<q-toggle
|
||||
v-model="template.agent_script_actions"
|
||||
label="Agents"
|
||||
color="green"
|
||||
left-label
|
||||
/>
|
||||
|
||||
<q-toggle v-model="template.check_script_actions" label="Checks" color="green" left-label />
|
||||
<q-toggle
|
||||
v-model="template.check_script_actions"
|
||||
label="Checks"
|
||||
color="green"
|
||||
left-label
|
||||
/>
|
||||
|
||||
<q-toggle v-model="template.task_script_actions" label="Tasks" color="green" left-label />
|
||||
<q-toggle
|
||||
v-model="template.task_script_actions"
|
||||
label="Tasks"
|
||||
color="green"
|
||||
left-label
|
||||
/>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</q-step>
|
||||
@@ -246,9 +333,11 @@
|
||||
<span style="text-decoration: underline; cursor: help"
|
||||
>Alert Failure Settings
|
||||
<q-tooltip>
|
||||
Select what notifications should be sent when an agent is overdue. Enabled will override the agent
|
||||
notification setting sand always notify. Not configured will use what notification settings are
|
||||
configured on the agent. Disabled will override the agent notification settings and never notify.
|
||||
Select what notifications should be sent when an agent is
|
||||
overdue. Enabled will override the agent notification setting
|
||||
sand always notify. Not configured will use what notification
|
||||
settings are configured on the agent. Disabled will override
|
||||
the agent notification settings and never notify.
|
||||
</q-tooltip>
|
||||
</span>
|
||||
</div>
|
||||
@@ -282,19 +371,34 @@
|
||||
type="number"
|
||||
v-model.number="template.agent_periodic_alert_days"
|
||||
dense
|
||||
:rules="[val => val >= 0 || 'Periodic days must be 0 or greater']"
|
||||
:rules="[
|
||||
(val) => val >= 0 || 'Periodic days must be 0 or greater',
|
||||
]"
|
||||
/>
|
||||
</q-card-section>
|
||||
|
||||
<div class="q-pl-md text-subtitle1">
|
||||
<span style="text-decoration: underline; cursor: help"
|
||||
>Alert Resolved Settings
|
||||
<q-tooltip> Select what notifications should be sent when an overdue agent is back online. </q-tooltip>
|
||||
<q-tooltip>
|
||||
Select what notifications should be sent when an overdue agent
|
||||
is back online.
|
||||
</q-tooltip>
|
||||
</span>
|
||||
</div>
|
||||
<q-card-section>
|
||||
<q-toggle v-model="template.agent_email_on_resolved" label="Email" color="green" left-label />
|
||||
<q-toggle v-model="template.agent_text_on_resolved" label="Text" color="green" left-label />
|
||||
<q-toggle
|
||||
v-model="template.agent_email_on_resolved"
|
||||
label="Email"
|
||||
color="green"
|
||||
left-label
|
||||
/>
|
||||
<q-toggle
|
||||
v-model="template.agent_text_on_resolved"
|
||||
label="Text"
|
||||
color="green"
|
||||
left-label
|
||||
/>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</q-step>
|
||||
@@ -305,9 +409,11 @@
|
||||
<span style="text-decoration: underline; cursor: help"
|
||||
>Alert Failure Settings
|
||||
<q-tooltip>
|
||||
Select what notifications are sent when a check fails. Enabled will override the check notification
|
||||
settings and always notify. Not configured will use the notification settings configured on the check.
|
||||
Disabled will override the check notification settings and never notify.
|
||||
Select what notifications are sent when a check fails. Enabled
|
||||
will override the check notification settings and always
|
||||
notify. Not configured will use the notification settings
|
||||
configured on the check. Disabled will override the check
|
||||
notification settings and never notify.
|
||||
</q-tooltip>
|
||||
</span>
|
||||
</div>
|
||||
@@ -391,19 +497,34 @@
|
||||
type="number"
|
||||
v-model.number="template.check_periodic_alert_days"
|
||||
dense
|
||||
:rules="[val => val >= 0 || 'Periodic days must be 0 or greater']"
|
||||
:rules="[
|
||||
(val) => val >= 0 || 'Periodic days must be 0 or greater',
|
||||
]"
|
||||
/>
|
||||
</q-card-section>
|
||||
|
||||
<div class="q-pl-md text-subtitle1">
|
||||
<span style="text-decoration: underline; cursor: help"
|
||||
>Alert Resolved Settings
|
||||
<q-tooltip> Select what notifications are sent when a failed check is resolved. </q-tooltip>
|
||||
<q-tooltip>
|
||||
Select what notifications are sent when a failed check is
|
||||
resolved.
|
||||
</q-tooltip>
|
||||
</span>
|
||||
</div>
|
||||
<q-card-section>
|
||||
<q-toggle v-model="template.check_email_on_resolved" label="Email" color="green" left-label />
|
||||
<q-toggle v-model="template.check_text_on_resolved" label="Text" color="green" left-label />
|
||||
<q-toggle
|
||||
v-model="template.check_email_on_resolved"
|
||||
label="Email"
|
||||
color="green"
|
||||
left-label
|
||||
/>
|
||||
<q-toggle
|
||||
v-model="template.check_text_on_resolved"
|
||||
label="Text"
|
||||
color="green"
|
||||
left-label
|
||||
/>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</q-step>
|
||||
@@ -414,9 +535,11 @@
|
||||
<span style="text-decoration: underline; cursor: help"
|
||||
>Alert Failure Settings
|
||||
<q-tooltip>
|
||||
Select what notifications are sent when an automated task fails. Enabled will override the task
|
||||
notification settings and always notify. Not configured will use the notification settings configured
|
||||
on the task. Disabled will override the task notification settings and never notify.
|
||||
Select what notifications are sent when an automated task
|
||||
fails. Enabled will override the task notification settings
|
||||
and always notify. Not configured will use the notification
|
||||
settings configured on the task. Disabled will override the
|
||||
task notification settings and never notify.
|
||||
</q-tooltip>
|
||||
</span>
|
||||
</div>
|
||||
@@ -500,19 +623,34 @@
|
||||
type="number"
|
||||
v-model.number="template.task_periodic_alert_days"
|
||||
dense
|
||||
:rules="[val => val >= 0 || 'Periodic days must be 0 or greater']"
|
||||
:rules="[
|
||||
(val) => val >= 0 || 'Periodic days must be 0 or greater',
|
||||
]"
|
||||
/>
|
||||
</q-card-section>
|
||||
|
||||
<div class="q-pl-md text-subtitle1">
|
||||
<span style="text-decoration: underline; cursor: help"
|
||||
>Alert Resolved Settings
|
||||
<q-tooltip> Select what notifications are sent when a failed task is resolved. </q-tooltip>
|
||||
<q-tooltip>
|
||||
Select what notifications are sent when a failed task is
|
||||
resolved.
|
||||
</q-tooltip>
|
||||
</span>
|
||||
</div>
|
||||
<q-card-section>
|
||||
<q-toggle v-model="template.task_email_on_resolved" label="Email" color="green" left-label />
|
||||
<q-toggle v-model="template.check_text_on_resolved" label="Text" color="green" left-label />
|
||||
<q-toggle
|
||||
v-model="template.task_email_on_resolved"
|
||||
label="Email"
|
||||
color="green"
|
||||
left-label
|
||||
/>
|
||||
<q-toggle
|
||||
v-model="template.check_text_on_resolved"
|
||||
label="Text"
|
||||
color="green"
|
||||
left-label
|
||||
/>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</q-step>
|
||||
@@ -526,7 +664,12 @@
|
||||
label="Back"
|
||||
class="q-mr-xs"
|
||||
/>
|
||||
<q-btn v-if="step < 5" @click="$refs.stepper.next()" color="primary" label="Next" />
|
||||
<q-btn
|
||||
v-if="step < 5"
|
||||
@click="$refs.stepper.next()"
|
||||
color="primary"
|
||||
label="Next"
|
||||
/>
|
||||
<q-space />
|
||||
<q-btn @click="onSubmit" color="primary" label="Submit" />
|
||||
</q-stepper-navigation>
|
||||
@@ -615,10 +758,14 @@ export default {
|
||||
methods: {
|
||||
setScriptDefaults(type) {
|
||||
if (type === "failure") {
|
||||
const script = this.scriptOptions.find(i => i.value === this.template.action);
|
||||
const script = this.scriptOptions.find(
|
||||
(i) => i.value === this.template.action
|
||||
);
|
||||
this.template.action_args = script.args;
|
||||
} else if (type === "resolved") {
|
||||
const script = this.scriptOptions.find(i => i.value === this.template.resolved_action);
|
||||
const script = this.scriptOptions.find(
|
||||
(i) => i.value === this.template.resolved_action
|
||||
);
|
||||
this.template.resolved_action_args = script.args;
|
||||
}
|
||||
},
|
||||
@@ -628,14 +775,14 @@ export default {
|
||||
title: "Add email",
|
||||
prompt: {
|
||||
model: "",
|
||||
isValid: val => this.isValidEmail(val),
|
||||
isValid: (val) => this.isValidEmail(val),
|
||||
type: "email",
|
||||
},
|
||||
cancel: true,
|
||||
ok: { label: "Add", color: "primary" },
|
||||
persistent: false,
|
||||
})
|
||||
.onOk(data => {
|
||||
.onOk((data) => {
|
||||
this.template.email_recipients.push(data);
|
||||
});
|
||||
},
|
||||
@@ -653,16 +800,16 @@ export default {
|
||||
ok: { label: "Add", color: "primary" },
|
||||
persistent: false,
|
||||
})
|
||||
.onOk(data => {
|
||||
.onOk((data) => {
|
||||
this.template.text_recipients.push(data);
|
||||
});
|
||||
},
|
||||
removeEmail(email) {
|
||||
const removed = this.template.email_recipients.filter(k => k !== email);
|
||||
const removed = this.template.email_recipients.filter((k) => k !== email);
|
||||
this.template.email_recipients = removed;
|
||||
},
|
||||
removeSMSNumber(num) {
|
||||
const removed = this.template.text_recipients.filter(k => k !== num);
|
||||
const removed = this.template.text_recipients.filter((k) => k !== num);
|
||||
this.template.text_recipients = removed;
|
||||
},
|
||||
onSubmit() {
|
||||
@@ -676,23 +823,23 @@ export default {
|
||||
if (this.editing) {
|
||||
this.$axios
|
||||
.put(`alerts/templates/${this.template.id}/`, this.template)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.$q.loading.hide();
|
||||
this.onOk();
|
||||
this.notifySuccess("Alert Template edited!");
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
} else {
|
||||
this.$axios
|
||||
.post("alerts/templates/", this.template)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.$q.loading.hide();
|
||||
this.onOk();
|
||||
this.notifySuccess(`Alert Template was added!`);
|
||||
this.notifySuccess("Alert Template was added!");
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
}
|
||||
@@ -712,7 +859,9 @@ export default {
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getScriptOptions(this.showCommunityScripts).then(options => (this.scriptOptions = Object.freeze(options)));
|
||||
this.getScriptOptions(this.showCommunityScripts).then(
|
||||
(options) => (this.scriptOptions = Object.freeze(options))
|
||||
);
|
||||
// Copy alertTemplate prop locally
|
||||
if (this.editing) Object.assign(this.template, this.alertTemplate);
|
||||
},
|
||||
|
@@ -100,11 +100,11 @@ export default {
|
||||
|
||||
this.$axios
|
||||
.get(`/alerts/templates/${this.template.id}/related/`)
|
||||
.then(r => {
|
||||
.then((r) => {
|
||||
this.$q.loading.hide();
|
||||
this.related = r.data;
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
|
@@ -1,5 +1,11 @@
|
||||
<template>
|
||||
<q-dialog ref="dialog" @hide="onHide" maximized transition-show="slide-up" transition-hide="slide-down">
|
||||
<q-dialog
|
||||
ref="dialog"
|
||||
@hide="onHide"
|
||||
maximized
|
||||
transition-show="slide-up"
|
||||
transition-hide="slide-down"
|
||||
>
|
||||
<q-card>
|
||||
<q-bar>
|
||||
<q-btn @click="search" class="q-mr-sm" dense flat push icon="refresh" />
|
||||
@@ -40,11 +46,29 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="q-pa-sm col-2">
|
||||
<q-select outlined dense v-model="timeFilter" label="Time" emit-value map-options :options="timeOptions" />
|
||||
<q-select
|
||||
outlined
|
||||
dense
|
||||
v-model="timeFilter"
|
||||
label="Time"
|
||||
emit-value
|
||||
map-options
|
||||
:options="timeOptions"
|
||||
/>
|
||||
</div>
|
||||
<div class="q-pa-sm col-2">
|
||||
<q-checkbox outlined dense v-model="includeSnoozed" label="Include snoozed" />
|
||||
<q-checkbox outlined dense v-model="includeResolved" label="Include resolved" />
|
||||
<q-checkbox
|
||||
outlined
|
||||
dense
|
||||
v-model="includeSnoozed"
|
||||
label="Include snoozed"
|
||||
/>
|
||||
<q-checkbox
|
||||
outlined
|
||||
dense
|
||||
v-model="includeResolved"
|
||||
label="Include resolved"
|
||||
/>
|
||||
</div>
|
||||
<div class="q-pa-sm col-2">
|
||||
<q-btn color="primary" label="Search" @click="search" />
|
||||
@@ -55,7 +79,10 @@
|
||||
|
||||
<q-card-section>
|
||||
<q-table
|
||||
:table-class="{ 'table-bgcolor': !$q.dark.isActive, 'table-bgcolor-dark': $q.dark.isActive }"
|
||||
:table-class="{
|
||||
'table-bgcolor': !$q.dark.isActive,
|
||||
'table-bgcolor-dark': $q.dark.isActive,
|
||||
}"
|
||||
class="audit-mgr-tbl-sticky"
|
||||
:rows="alerts"
|
||||
:columns="columns"
|
||||
@@ -73,9 +100,17 @@
|
||||
<template v-slot:top>
|
||||
<div class="col-1 q-table__title">Alerts</div>
|
||||
|
||||
<q-btn-dropdown flat label="Bulk Actions" :disable="selectedAlerts.length === 0 || includeResolved">
|
||||
<q-btn-dropdown
|
||||
flat
|
||||
label="Bulk Actions"
|
||||
:disable="selectedAlerts.length === 0 || includeResolved"
|
||||
>
|
||||
<q-list dense>
|
||||
<q-item clickable v-close-popup @click="snoozeAlertBulk(selectedAlerts)">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="snoozeAlertBulk(selectedAlerts)"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-icon name="alarm_off" />
|
||||
</q-item-section>
|
||||
@@ -83,7 +118,11 @@
|
||||
<q-item-label>Snooze alerts</q-item-label>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable v-close-popup @click="resolveAlertBulk(selectedAlerts)">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="resolveAlertBulk(selectedAlerts)"
|
||||
>
|
||||
<q-item-section avatar>
|
||||
<q-icon name="flag" />
|
||||
</q-item-section>
|
||||
@@ -147,7 +186,9 @@
|
||||
|
||||
<template v-slot:body-cell-severity="props">
|
||||
<q-td :props="props">
|
||||
<q-badge :color="alertColor(props.row.severity)">{{ capitalize(props.row.severity) }}</q-badge>
|
||||
<q-badge :color="alertColor(props.row.severity)">{{
|
||||
capitalize(props.row.severity)
|
||||
}}</q-badge>
|
||||
</q-td>
|
||||
</template>
|
||||
|
||||
@@ -184,7 +225,7 @@ export default {
|
||||
name: "AlertsOverview",
|
||||
emits: ["hide"],
|
||||
mixins: [mixins],
|
||||
setup(props) {
|
||||
setup() {
|
||||
// setup vuex store
|
||||
const store = useStore();
|
||||
const formatDate = computed(() => store.getters.formatDate);
|
||||
@@ -225,17 +266,35 @@ export default {
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{ name: "hostname", label: "Agent", field: "hostname", align: "left", sortable: true },
|
||||
{
|
||||
name: "hostname",
|
||||
label: "Agent",
|
||||
field: "hostname",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "alert_type",
|
||||
label: "Type",
|
||||
field: "alert_type",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
format: a => this.capitalize(a, true),
|
||||
format: (a) => this.capitalize(a, true),
|
||||
},
|
||||
{
|
||||
name: "severity",
|
||||
label: "Severity",
|
||||
field: "severity",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "message",
|
||||
label: "Message",
|
||||
field: "message",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{ name: "severity", label: "Severity", field: "severity", align: "left", sortable: true },
|
||||
{ name: "message", label: "Message", field: "message", align: "left", sortable: true },
|
||||
{
|
||||
name: "resolve_on",
|
||||
label: "Resolved On",
|
||||
@@ -261,10 +320,12 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
noDataText() {
|
||||
return this.searched ? "No data found. Try to refine you search" : "Click search to find alerts";
|
||||
return this.searched
|
||||
? "No data found. Try to refine you search"
|
||||
: "Click search to find alerts";
|
||||
},
|
||||
visibleColumns() {
|
||||
return this.columns.map(column => {
|
||||
return this.columns.map((column) => {
|
||||
if (column.name === "snoozed_until") {
|
||||
if (this.includeSnoozed) return column.name;
|
||||
} else if (column.name === "resolve_on") {
|
||||
@@ -277,12 +338,11 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
getClients() {
|
||||
this.$axios
|
||||
.get("/clients/")
|
||||
.then(r => {
|
||||
this.clientsOptions = Object.freeze(r.data.map(client => ({ label: client.name, value: client.id })));
|
||||
})
|
||||
.catch(e => {});
|
||||
this.$axios.get("/clients/").then((r) => {
|
||||
this.clientsOptions = Object.freeze(
|
||||
r.data.map((client) => ({ label: client.name, value: client.id }))
|
||||
);
|
||||
});
|
||||
},
|
||||
search() {
|
||||
this.$q.loading.show();
|
||||
@@ -295,17 +355,19 @@ export default {
|
||||
resolvedFilter: this.includeResolved,
|
||||
};
|
||||
|
||||
if (this.clientFilter.length > 0) data["clientFilter"] = this.clientFilter;
|
||||
if (this.clientFilter.length > 0)
|
||||
data["clientFilter"] = this.clientFilter;
|
||||
if (this.timeFilter) data["timeFilter"] = this.timeFilter;
|
||||
if (this.severityFilter.length > 0) data["severityFilter"] = this.severityFilter;
|
||||
if (this.severityFilter.length > 0)
|
||||
data["severityFilter"] = this.severityFilter;
|
||||
|
||||
this.$axios
|
||||
.patch("/alerts/", data)
|
||||
.then(r => {
|
||||
.then((r) => {
|
||||
this.$q.loading.hide();
|
||||
this.alerts = Object.freeze(r.data);
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
@@ -317,11 +379,11 @@ export default {
|
||||
prompt: {
|
||||
model: "",
|
||||
type: "number",
|
||||
isValid: val => !!val && val > 0 && val < 9999,
|
||||
isValid: (val) => !!val && val > 0 && val < 9999,
|
||||
},
|
||||
cancel: true,
|
||||
})
|
||||
.onOk(days => {
|
||||
.onOk((days) => {
|
||||
this.$q.loading.show();
|
||||
|
||||
const data = {
|
||||
@@ -332,12 +394,12 @@ export default {
|
||||
|
||||
this.$axios
|
||||
.put(`alerts/${alert.id}/`, data)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.search();
|
||||
this.$q.loading.hide();
|
||||
this.notifySuccess(`The alert has been snoozed for ${days} days`);
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
});
|
||||
@@ -352,12 +414,12 @@ export default {
|
||||
|
||||
this.$axios
|
||||
.put(`alerts/${alert.id}/`, data)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.search();
|
||||
this.$q.loading.hide();
|
||||
this.notifySuccess(`The alert has been unsnoozed`);
|
||||
this.notifySuccess("The alert has been unsnoozed");
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
@@ -371,12 +433,12 @@ export default {
|
||||
|
||||
this.$axios
|
||||
.put(`alerts/${alert.id}/`, data)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.search();
|
||||
this.$q.loading.hide();
|
||||
this.notifySuccess("The alert has been resolved");
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
@@ -384,18 +446,18 @@ export default {
|
||||
this.$q.loading.show();
|
||||
|
||||
const data = {
|
||||
alerts: alerts.map(alert => alert.id),
|
||||
alerts: alerts.map((alert) => alert.id),
|
||||
bulk_action: "resolve",
|
||||
};
|
||||
|
||||
this.$axios
|
||||
.post("alerts/bulk/", data)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.search();
|
||||
this.$q.loading.hide();
|
||||
this.notifySuccess("Alerts were resolved");
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
@@ -407,27 +469,27 @@ export default {
|
||||
prompt: {
|
||||
model: "",
|
||||
type: "number",
|
||||
isValid: val => !!val && val > 0 && val < 9999,
|
||||
isValid: (val) => !!val && val > 0 && val < 9999,
|
||||
},
|
||||
cancel: true,
|
||||
})
|
||||
.onOk(days => {
|
||||
.onOk((days) => {
|
||||
this.$q.loading.show();
|
||||
|
||||
const data = {
|
||||
alerts: alerts.map(alert => alert.id),
|
||||
alerts: alerts.map((alert) => alert.id),
|
||||
bulk_action: "snooze",
|
||||
snooze_days: days,
|
||||
};
|
||||
|
||||
this.$axios
|
||||
.post("alerts/bulk/", data)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.search();
|
||||
this.$q.loading.hide();
|
||||
this.notifySuccess(`Alerts were snoozed for ${days} days`);
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
});
|
||||
|
@@ -13,7 +13,7 @@
|
||||
<q-form @submit.prevent="submit">
|
||||
<q-card-section>
|
||||
<q-select
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
outlined
|
||||
options-dense
|
||||
label="Actions"
|
||||
@@ -29,7 +29,11 @@
|
||||
<q-checkbox v-model="prune_tables" val="audit_logs" label="Audit Log">
|
||||
<q-tooltip>Removes agent check results</q-tooltip>
|
||||
</q-checkbox>
|
||||
<q-checkbox v-model="prune_tables" val="pending_actions" label="Pending Actions">
|
||||
<q-checkbox
|
||||
v-model="prune_tables"
|
||||
val="pending_actions"
|
||||
label="Pending Actions"
|
||||
>
|
||||
<q-tooltip>Removes completed pending actions</q-tooltip>
|
||||
</q-checkbox>
|
||||
<q-checkbox v-model="prune_tables" val="alerts" label="Alerts">
|
||||
@@ -38,7 +42,12 @@
|
||||
</q-card-section>
|
||||
|
||||
<q-card-actions align="left">
|
||||
<q-btn label="Submit" color="primary" type="submit" class="full-width" />
|
||||
<q-btn
|
||||
label="Submit"
|
||||
color="primary"
|
||||
type="submit"
|
||||
class="full-width"
|
||||
/>
|
||||
</q-card-actions>
|
||||
</q-form>
|
||||
</q-card-section>
|
||||
@@ -85,11 +94,11 @@ export default {
|
||||
|
||||
this.$axios
|
||||
.post("core/servermaintenance/", data)
|
||||
.then(r => {
|
||||
.then((r) => {
|
||||
this.$q.loading.hide();
|
||||
this.notifySuccess(r.data);
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
|
@@ -13,7 +13,10 @@
|
||||
class="full-width"
|
||||
@click="doCodeSign"
|
||||
>
|
||||
<q-tooltip>Force all existing agents to be updated to the code-signed version</q-tooltip>
|
||||
<q-tooltip
|
||||
>Force all existing agents to be updated to the code-signed
|
||||
version</q-tooltip
|
||||
>
|
||||
</q-btn>
|
||||
</q-card-section>
|
||||
<q-form @submit.prevent="editToken">
|
||||
@@ -25,7 +28,7 @@
|
||||
dense
|
||||
v-model="settings.token"
|
||||
class="col-9 q-pa-none"
|
||||
:rules="[val => !!val || 'Token is required']"
|
||||
:rules="[(val) => !!val || 'Token is required']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section class="row items-center">
|
||||
@@ -49,22 +52,19 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
getToken() {
|
||||
this.$axios
|
||||
.get("/core/codesign/")
|
||||
.then(r => {
|
||||
this.$axios.get("/core/codesign/").then((r) => {
|
||||
this.settings = r.data;
|
||||
})
|
||||
.catch(e => {});
|
||||
});
|
||||
},
|
||||
editToken() {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.patch("/core/codesign/", this.settings)
|
||||
.then(r => {
|
||||
.then((r) => {
|
||||
this.$q.loading.hide();
|
||||
this.notifySuccess(r.data);
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
@@ -72,7 +72,7 @@ export default {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.post("/core/codesign/")
|
||||
.then(r => {
|
||||
.then((r) => {
|
||||
this.$q.loading.hide();
|
||||
this.notifySuccess(r.data);
|
||||
})
|
||||
|
@@ -34,7 +34,10 @@
|
||||
<q-scroll-area :thumb-style="thumbStyle" style="height: 50vh">
|
||||
<q-tab-panels v-model="tab" :animated="false">
|
||||
<q-tab-panel name="client">
|
||||
<CustomFieldsTable @refresh="getCustomFields" :data="clientFields" />
|
||||
<CustomFieldsTable
|
||||
@refresh="getCustomFields"
|
||||
:data="clientFields"
|
||||
/>
|
||||
</q-tab-panel>
|
||||
|
||||
<q-tab-panel name="site">
|
||||
@@ -74,13 +77,13 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
agentFields() {
|
||||
return this.customFields.filter(field => field.model === "agent");
|
||||
return this.customFields.filter((field) => field.model === "agent");
|
||||
},
|
||||
siteFields() {
|
||||
return this.customFields.filter(field => field.model === "site");
|
||||
return this.customFields.filter((field) => field.model === "site");
|
||||
},
|
||||
clientFields() {
|
||||
return this.customFields.filter(field => field.model === "client");
|
||||
return this.customFields.filter((field) => field.model === "client");
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
@@ -88,12 +91,12 @@ export default {
|
||||
this.$q.loading.show();
|
||||
|
||||
this.$axios
|
||||
.get(`/core/customfields/`)
|
||||
.then(r => {
|
||||
.get("/core/customfields/")
|
||||
.then((r) => {
|
||||
this.$q.loading.hide();
|
||||
this.customFields = r.data;
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
|
@@ -20,12 +20,18 @@
|
||||
dense
|
||||
:disable="editing"
|
||||
v-model="localField.model"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<!-- name -->
|
||||
<q-card-section>
|
||||
<q-input label="Name" outlined dense v-model="localField.name" :rules="[val => !!val || '*Required']" />
|
||||
<q-input
|
||||
label="Name"
|
||||
outlined
|
||||
dense
|
||||
v-model="localField.name"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<!-- type select -->
|
||||
<q-card-section>
|
||||
@@ -39,11 +45,13 @@
|
||||
dense
|
||||
:disable="editing"
|
||||
v-model="localField.type"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
:rules="[(val) => !!val || '*Required']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<!-- input options select for single and multiple input type -->
|
||||
<q-card-section v-if="localField.type === 'single' || localField.type == 'multiple'">
|
||||
<q-card-section
|
||||
v-if="localField.type === 'single' || localField.type == 'multiple'"
|
||||
>
|
||||
<q-select
|
||||
dense
|
||||
label="Input Options (press Enter after typing each option)"
|
||||
@@ -129,7 +137,11 @@
|
||||
v-model="localField.required"
|
||||
color="green"
|
||||
/>
|
||||
<q-toggle label="Hide in Dashboard" v-model="localField.hide_in_ui" color="green" />
|
||||
<q-toggle
|
||||
label="Hide in Dashboard"
|
||||
v-model="localField.hide_in_ui"
|
||||
color="green"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-actions align="right">
|
||||
<q-btn flat label="Cancel" v-close-popup />
|
||||
@@ -185,7 +197,9 @@ export default {
|
||||
},
|
||||
defaultValueRules() {
|
||||
if (this.localField.required) {
|
||||
return [val => !!val || `Default Value needs to be set for required fields`];
|
||||
return [
|
||||
(val) => !!val || "Default Value needs to be set for required fields",
|
||||
];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
@@ -202,23 +216,23 @@ export default {
|
||||
if (this.editing) {
|
||||
this.$axios
|
||||
.put(`/core/customfields/${data.id}/`, data)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.$q.loading.hide();
|
||||
this.onOk();
|
||||
this.notifySuccess("Custom field edited!");
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
} else {
|
||||
this.$axios
|
||||
.post("/core/customfields/", data)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.$q.loading.hide();
|
||||
this.onOk();
|
||||
this.notifySuccess("Custom field added!");
|
||||
})
|
||||
.catch(e => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
}
|
||||
|
@@ -13,7 +13,11 @@
|
||||
>
|
||||
<!-- body slots -->
|
||||
<template v-slot:body="props">
|
||||
<q-tr :props="props" class="cursor-pointer" @dblclick="editCustomField(props.row)">
|
||||
<q-tr
|
||||
:props="props"
|
||||
class="cursor-pointer"
|
||||
@dblclick="editCustomField(props.row)"
|
||||
>
|
||||
<!-- context menu -->
|
||||
<q-menu context-menu>
|
||||
<q-list dense style="min-width: 200px">
|
||||
@@ -23,7 +27,11 @@
|
||||
</q-item-section>
|
||||
<q-item-section>Edit</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable v-close-popup @click="deleteCustomField(props.row)">
|
||||
<q-item
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="deleteCustomField(props.row)"
|
||||
>
|
||||
<q-item-section side>
|
||||
<q-icon name="delete" />
|
||||
</q-item-section>
|
||||
@@ -54,13 +62,17 @@
|
||||
{{ props.row.default_value_bool }}
|
||||
</q-td>
|
||||
<q-td v-else-if="props.row.type === 'multiple'">
|
||||
<span v-if="props.row.default_values_multiple.length > 0">{{ props.row.default_values_multiple }}</span>
|
||||
<span v-if="props.row.default_values_multiple.length > 0">{{
|
||||
props.row.default_values_multiple
|
||||
}}</span>
|
||||
</q-td>
|
||||
<q-td v-else>
|
||||
{{ truncateText(props.row.default_value_string) }}
|
||||
<q-tooltip v-if="props.row.default_value_string.length >= 60" style="font-size: 12px">{{
|
||||
props.row.default_value_string
|
||||
}}</q-tooltip>
|
||||
<q-tooltip
|
||||
v-if="props.row.default_value_string.length >= 60"
|
||||
style="font-size: 12px"
|
||||
>{{ props.row.default_value_string }}</q-tooltip
|
||||
>
|
||||
</q-td>
|
||||
<!-- required -->
|
||||
<q-td>
|
||||
@@ -104,9 +116,27 @@ export default {
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{ name: "hide_in_ui", label: "Hide in UI", field: "hide_in_ui", align: "left", sortable: true },
|
||||
{ name: "default_value", label: "Default Value", field: "default_value", align: "left", sortable: true },
|
||||
{ name: "required", label: "Required", field: "required", align: "left", sortable: true },
|
||||
{
|
||||
name: "hide_in_ui",
|
||||
label: "Hide in UI",
|
||||
field: "hide_in_ui",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "default_value",
|
||||
label: "Default Value",
|
||||
field: "default_value",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "required",
|
||||
label: "Required",
|
||||
field: "required",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
@@ -134,12 +164,12 @@ export default {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.delete(`/core/customfields/${field.id}/`)
|
||||
.then(r => {
|
||||
.then(() => {
|
||||
this.refresh();
|
||||
this.$q.loading.hide();
|
||||
this.notifySuccess(`Custom Field ${field.name} was deleted!`);
|
||||
})
|
||||
.catch(error => {
|
||||
.catch(() => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
});
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user