Compare commits

...

48 Commits

Author SHA1 Message Date
wh1te909
8c6ac164ba bump dev ver 2023-04-07 22:46:24 +00:00
wh1te909
dc68b16ff2 format and align the icon 2023-04-07 21:52:53 +00:00
Dan
a4f15fd05a Merge pull request #6 from jpros/custom-fields-in-summary
Add custom fields to summary view
2023-04-07 13:51:50 -07:00
wh1te909
176675abd8 update reqs 2023-04-07 20:50:21 +00:00
João Paulo Ros
73dc278ac4 Hide custom fields with no value 2023-04-04 20:36:53 -07:00
wh1te909
d6b443296b update reqs 2023-04-04 06:34:11 +00:00
Dan
f3c718d29c Merge pull request #7 from jpros/custom-fields-search
Add custom fields to search in the dashboard
2023-04-03 22:46:20 -07:00
João Paulo Ros
5955af08c7 Hide custom fields that are not supposed to appear in the UI. 2023-03-31 15:22:10 -07:00
João Paulo Ros
dec1ccc98a Add Search from query parameter 2023-03-30 15:40:47 -07:00
João Paulo Ros
a78780b837 Add custom fields to summary view 2023-03-30 14:38:55 -07:00
João Paulo Ros
beff8eb10e Add custom fields to search in dashboard 2023-03-30 12:37:26 -07:00
wh1te909
c2f21b70dd bump version 2023-03-22 16:59:35 +00:00
wh1te909
520145e0e3 bump dev ver 2023-03-21 18:49:28 +00:00
wh1te909
6a132187a2 fix phantom column fixes amidaware/tacticalrmm#1264 2023-03-20 14:08:58 +00:00
wh1te909
a63a9ccd76 update reqs 2023-03-20 01:28:54 +00:00
wh1te909
ff1eb791db feat: increase size of notes text box closes amidaware/tacticalrmm#1407 2023-03-10 05:31:50 +00:00
wh1te909
13bd88b979 feat: bulk run checks by client or site amidaware/tacticalrmm@7d017f9494 2023-03-10 00:22:12 +00:00
wh1te909
5b0c244920 update reqs 2023-03-10 00:20:51 +00:00
wh1te909
0318a17cac update reqs 2023-03-05 20:49:03 +00:00
wh1te909
75296ed8ee bump version 2023-01-18 20:04:26 +00:00
wh1te909
09bee45b2f update reqs and dev version 2023-01-16 23:03:30 +00:00
wh1te909
3573c48872 formatting 2023-01-16 08:38:34 +00:00
wh1te909
784841c221 syntax typo 2023-01-16 08:37:15 +00:00
wh1te909
ed788a1861 update reqs 2023-01-16 08:35:07 +00:00
wh1te909
bd6b08505a bump version 2022-12-21 18:44:21 +00:00
wh1te909
acd64f25f2 add ui for self reset amidaware/tacticalrmm#1378 2022-12-20 23:38:19 +00:00
wh1te909
087be2c232 update reqs 2022-12-20 23:35:44 +00:00
wh1te909
91a3272843 format 2022-12-20 23:35:32 +00:00
wh1te909
6e64f0a11b formatting 2022-12-20 21:02:55 +00:00
wh1te909
8f34f76a1d fix edit apikey amidaware/tacticalrmm#1369 2022-12-08 23:27:26 +00:00
wh1te909
d87861c212 bump version 2022-12-04 23:01:35 +00:00
wh1te909
5f56e7017b bump dev 2022-12-03 07:47:28 +00:00
wh1te909
9c033c1c90 feat: env vars 2022-12-01 00:44:56 +00:00
wh1te909
ba14ed348e update reqs 2022-12-01 00:37:44 +00:00
wh1te909
7e25db6622 bump version 2022-11-13 01:20:19 +00:00
wh1te909
78636c436f update reqs 2022-11-08 07:24:55 +00:00
wh1te909
d37122386f bump version 2022-10-25 22:02:23 +00:00
wh1te909
17d960fca9 update reqs 2022-10-25 06:36:07 +00:00
wh1te909
d2e0b8ad9b fix function call 2022-10-23 08:04:32 +00:00
wh1te909
776c27ec26 bump version 2022-10-19 22:33:09 +00:00
wh1te909
41c61ce152 update reqs 2022-10-19 06:50:50 +00:00
wh1te909
8e9de8b6b6 check if token expired 2022-10-19 06:47:16 +00:00
wh1te909
4cf5f7a3cb update reqs 2022-10-18 00:20:02 +00:00
wh1te909
9729492d1c make link readable in dark mode amidaware/tacticalrmm#1314 2022-10-14 02:06:15 +00:00
wh1te909
d6da8b4a96 bump version 2022-09-24 02:10:26 +00:00
wh1te909
9264cf4044 change dl command 2022-09-24 02:10:03 +00:00
wh1te909
3a45c2a309 mac agent 2022-09-23 22:58:56 +00:00
wh1te909
59de35c698 update reqs 2022-09-23 16:18:06 +00:00
35 changed files with 3016 additions and 4252 deletions

View File

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

View File

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

View File

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

6562
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{ {
"name": "web", "name": "web",
"version": "0.100.9", "version": "0.101.17-dev",
"private": true, "private": true,
"productName": "Tactical RMM", "productName": "Tactical RMM",
"scripts": { "scripts": {
@@ -10,31 +10,31 @@
"format": "prettier --write \"**/*.{js,ts,vue,,html,md,json}\" --ignore-path .gitignore" "format": "prettier --write \"**/*.{js,ts,vue,,html,md,json}\" --ignore-path .gitignore"
}, },
"dependencies": { "dependencies": {
"@quasar/extras": "1.15.1", "@quasar/extras": "1.16.2",
"apexcharts": "3.35.4", "apexcharts": "3.37.3",
"axios": "0.27.2", "axios": "1.3.5",
"dotenv": "16.0.1", "dotenv": "16.0.3",
"qrcode.vue": "3.3.3", "qrcode.vue": "3.3.4",
"quasar": "2.7.7", "quasar": "2.11.10",
"vue": "3.2.37", "vue": "3.2.47",
"vue3-ace-editor": "2.2.2", "vue3-ace-editor": "2.2.2",
"vue3-apexcharts": "1.4.1", "vue3-apexcharts": "1.4.1",
"vuedraggable": "4.1.0", "vuedraggable": "4.1.0",
"vue-router": "4.1.3", "vue-router": "4.1.6",
"vuex": "4.0.2" "vuex": "4.1.0"
}, },
"devDependencies": { "devDependencies": {
"@quasar/cli": "^1.3.2", "@quasar/cli": "^2.0.0",
"@intlify/vite-plugin-vue-i18n": "^6.0.0", "@intlify/unplugin-vue-i18n": "^0.10.0",
"@quasar/app-vite": "^1.0.6", "@quasar/app-vite": "^1.2.1",
"@types/node": "^18.6.5", "@types/node": "^18.15.11",
"@typescript-eslint/eslint-plugin": "^5.33.0", "@typescript-eslint/eslint-plugin": "^5.57.1",
"@typescript-eslint/parser": "^5.33.0", "@typescript-eslint/parser": "^5.57.1",
"autoprefixer": "^10.4.7", "autoprefixer": "10.4.14",
"eslint": "^8.21.0", "eslint": "8.37.0",
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "8.8.0",
"eslint-plugin-vue": "^8.5.0", "eslint-plugin-vue": "8.7.1",
"prettier": "^2.7.1", "prettier": "2.8.7",
"typescript": "^4.7.4" "typescript": "5.0.4"
} }
} }

View File

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

View File

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

View File

@@ -196,6 +196,14 @@
> >
<q-tooltip>Linux</q-tooltip> <q-tooltip>Linux</q-tooltip>
</q-icon> </q-icon>
<q-icon
v-else-if="props.row.plat === 'darwin'"
name="mdi-apple"
size="sm"
color="primary"
>
<q-tooltip>macOS</q-tooltip>
</q-icon>
</q-td> </q-td>
<q-td key="checks-status" :props="props"> <q-td key="checks-status" :props="props">
@@ -365,17 +373,12 @@ export default {
"local_ips", "local_ips",
"make_model", "make_model",
"physical_disks", "physical_disks",
"custom_fields"
]; ];
// quasar filter only does visible columns so this is a hack to add hidden columns we want to filter // quasar filter only does visible columns so this is a hack to add hidden columns we want to filter
for (const elem of hiddenFields) { // originally I was modifying cols directly but this led to phantom colum so doing it this way now
if (!cols.find((o) => o.name === elem)) { // https://github.com/amidaware/tacticalrmm/issues/1264
cols.push({ const allColumns = [...cols, ...hiddenFields.map((field) => ({ field }))];
name: elem,
field: elem,
});
}
}
const lowerTerms = terms ? terms.toLowerCase() : ""; const lowerTerms = terms ? terms.toLowerCase() : "";
let advancedFilter = false; let advancedFilter = false;
@@ -429,8 +432,12 @@ export default {
} }
// Normal text filter // Normal text filter
return cols.some((col) => { return allColumns.some((col) => {
const val = cellValue(col, row) + ""; let valObj = cellValue(col, row);
if (Array.isArray(valObj)) {
valObj = valObj.map((item) => item.value ? item.value : item);
}
const val = valObj + "";
const haystack = const haystack =
val === "undefined" || val === "null" ? "" : val.toLowerCase(); val === "undefined" || val === "null" ? "" : val.toLowerCase();
return haystack.indexOf(search) !== -1; return haystack.indexOf(search) !== -1;

View File

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

View File

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

View File

@@ -158,6 +158,20 @@
> >
</div> </div>
<div v-else>No checks</div> <div v-else>No checks</div>
<span
v-if="customFields.length > 0"
class="text-subtitle2 text-bold block q-mt-xl"
>Custom Fields</span
>
<q-list dense>
<q-item v-for="(field, i) in customFields" :key="field + i">
<q-item-section thumbnail>
<q-icon name="fas fa-user" size="xs" />
</q-item-section>
<q-item-section>{{ field.name }}: {{ field.value }}</q-item-section>
</q-item>
</q-list>
</div> </div>
<div class="col-1"></div> <div class="col-1"></div>
<!-- right --> <!-- right -->
@@ -193,6 +207,7 @@ import {
openAgentWindow, openAgentWindow,
} from "@/api/agents"; } from "@/api/agents";
import { notifySuccess } from "@/utils/notify"; import { notifySuccess } from "@/utils/notify";
import { fetchCustomFields } from "@/api/core";
// ui imports // ui imports
import AgentActionMenu from "@/components/agents/AgentActionMenu.vue"; import AgentActionMenu from "@/components/agents/AgentActionMenu.vue";
@@ -210,6 +225,7 @@ export default {
// summary tab logic // summary tab logic
const summary = ref(null); const summary = ref(null);
const customFieldsDefinitions = ref(null);
const loading = ref(false); const loading = ref(false);
function diskBarColor(percent) { function diskBarColor(percent) {
@@ -236,9 +252,37 @@ export default {
return ret; return ret;
}); });
const customFields = computed(() => {
if (!summary.value.custom_fields) {
return [];
}
if (!customFieldsDefinitions.value) {
return [];
}
const ret = [];
for (const customField of summary.value.custom_fields) {
const definition = customFieldsDefinitions.value.find(
(def) => def.id === customField.field
);
if (
definition &&
!definition.hide_in_ui &&
customField.value?.length > 0
) {
ret.push({
name: definition.name,
value: customField.value,
});
}
}
return ret;
});
async function getSummary() { async function getSummary() {
loading.value = true; loading.value = true;
summary.value = await fetchAgent(selectedAgent.value); summary.value = await fetchAgent(selectedAgent.value);
customFieldsDefinitions.value = await fetchCustomFields();
store.commit("setRefreshSummaryTab", false); store.commit("setRefreshSummaryTab", false);
store.commit("setAgentPlatform", summary.value.plat); store.commit("setAgentPlatform", summary.value.plat);
loading.value = false; loading.value = false;
@@ -277,6 +321,7 @@ export default {
return { return {
// reactive data // reactive data
summary, summary,
customFields,
loading, loading,
selectedAgent, selectedAgent,
disks, disks,

View File

@@ -310,9 +310,10 @@ export default {
} }
function showUpdateDetails(update) { function showUpdateDetails(update) {
const color = $q.dark.isActive ? "white" : "";
let support_urls = ""; let support_urls = "";
update.more_info_urls.forEach((u) => { update.more_info_urls.forEach((u) => {
support_urls += `<a href='${u}' target='_blank'>${u}</a><br/>`; support_urls += `<a style='color: ${color}' href='${u}' target='_blank'>${u}</a><br/>`;
}); });
let cats = update.categories.join(", "); let cats = update.categories.join(", ");
$q.dialog({ $q.dialog({

View File

@@ -42,10 +42,9 @@ export default {
const tabHeight = computed(() => store.state.tabHeight); const tabHeight = computed(() => store.state.tabHeight);
function copyValueToClip(val) { function copyValueToClip(val) {
copyToClipboard(val) copyToClipboard(val).then(() => {
.then(() => {
notifySuccess("Copied to clipboard"); notifySuccess("Copied to clipboard");
}) });
} }
return { return {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -118,6 +118,17 @@
new-value-mode="add" new-value-mode="add"
:readonly="readonly" :readonly="readonly"
/> />
<tactical-dropdown
v-model="formScript.env_vars"
:label="envVarsLabel"
filled
use-input
multiple
hide-dropdown-icon
input-debounce="0"
new-value-mode="add"
:readonly="readonly"
/>
<q-input <q-input
type="number" type="number"
filled filled
@@ -137,7 +148,7 @@
'Run As User' checkboxes in the UI and force this script to 'Run As User' checkboxes in the UI and force this script to
always be run in the context of the logged in user. If no user always be run in the context of the logged in user. If no user
is logged in, the script will not run and an error will be is logged in, the script will not run and an error will be
returned. Not supported on Windows Server. returned.
</q-tooltip> </q-tooltip>
</q-checkbox> </q-checkbox>
<q-input <q-input
@@ -229,6 +240,7 @@ import "ace-builds/src-noconflict/theme-tomorrow";
// static data // static data
import { shellOptions } from "@/composables/scripts"; import { shellOptions } from "@/composables/scripts";
import { envVarsLabel } from "@/constants/constants";
export default { export default {
name: "ScriptFormModal", name: "ScriptFormModal",
@@ -266,6 +278,7 @@ export default {
args: [], args: [],
script_body: "", script_body: "",
run_as_user: false, run_as_user: false,
env_vars: [],
}); });
if (props.clone) script.value.name = `(Copy) ${script.value.name}`; if (props.clone) script.value.name = `(Copy) ${script.value.name}`;
@@ -363,6 +376,7 @@ export default {
// non-reactive data // non-reactive data
shellOptions, shellOptions,
agentPlatformOptions, agentPlatformOptions,
envVarsLabel,
//computed //computed
title, title,

View File

@@ -867,7 +867,7 @@ export default {
} }
// component life cycle hooks // component life cycle hooks
onMounted(getScripts()); onMounted(getScripts);
return { return {
// reactive data // reactive data

View File

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

View File

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

View File

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

View File

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

View File

@@ -37,4 +37,5 @@ export function cmdPlaceholder(shell) {
export const agentPlatformOptions = [ export const agentPlatformOptions = [
{ value: "windows", label: "Windows" }, { value: "windows", label: "Windows" },
{ value: "linux", label: "Linux" }, { value: "linux", label: "Linux" },
{ value: "darwin", label: "macOS" },
]; ];

View File

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

View File

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

View File

@@ -14,6 +14,27 @@
@click="$store.dispatch('reload')" @click="$store.dispatch('reload')"
/> />
</q-banner> </q-banner>
<q-banner
v-if="!hosted && tokenExpired"
inline-actions
class="bg-yellow text-black text-center"
>
<q-icon size="xl" name="warning" />
<span
><br />Your code signing token is no longer valid.<br /><br />
If you have downgraded or cancelled your sponsorship, please delete
your token from the Code Signing modal and refresh to get rid of this
banner.<br /><br />
For any issues or to renew your sponsorship please email
support@amidaware.com<br /><br
/></span>
<q-btn
color="dark"
icon="refresh"
label="Refresh"
@click="$store.dispatch('reload')"
/>
</q-banner>
<q-toolbar> <q-toolbar>
<q-btn <q-btn
dense dense
@@ -119,6 +140,32 @@
<q-item-label>Preferences</q-item-label> <q-item-label>Preferences</q-item-label>
</q-item-section> </q-item-section>
</q-item> </q-item>
<q-item clickable>
<q-item-section>Account</q-item-section>
<q-item-section side>
<q-icon name="keyboard_arrow_right" />
</q-item-section>
<q-menu anchor="top end" self="top start">
<q-list>
<q-item
clickable
v-ripple
@click="resetPassword"
v-close-popup
>
<q-item-section>
<q-item-label>Reset Password</q-item-label>
</q-item-section>
</q-item>
<q-item clickable v-ripple @click="reset2FA" v-close-popup>
<q-item-section>
<q-item-label>Reset 2FA</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-item>
<q-item to="/expired" exact> <q-item to="/expired" exact>
<q-item-section> <q-item-section>
<q-item-label>Logout</q-item-label> <q-item-label>Logout</q-item-label>
@@ -140,10 +187,13 @@ import { useQuasar } from "quasar";
import { useStore } from "vuex"; import { useStore } from "vuex";
import axios from "axios"; import axios from "axios";
import { getWSUrl } from "@/websocket/channels"; import { getWSUrl } from "@/websocket/channels";
import { resetTwoFactor } from "@/api/accounts";
import { notifySuccess } from "@/utils/notify";
// ui imports // ui imports
import AlertsIcon from "@/components/AlertsIcon.vue"; import AlertsIcon from "@/components/AlertsIcon.vue";
import UserPreferences from "@/components/modals/coresettings/UserPreferences.vue"; import UserPreferences from "@/components/modals/coresettings/UserPreferences.vue";
import ResetPass from "@/components/accounts/ResetPass.vue";
export default { export default {
name: "MainLayout", name: "MainLayout",
@@ -167,6 +217,7 @@ export default {
const needRefresh = computed(() => store.state.needrefresh); const needRefresh = computed(() => store.state.needrefresh);
const user = computed(() => store.state.username); const user = computed(() => store.state.username);
const hosted = computed(() => store.state.hosted); const hosted = computed(() => store.state.hosted);
const tokenExpired = computed(() => store.state.tokenExpired);
const latestReleaseURL = computed(() => { const latestReleaseURL = computed(() => {
return latestTRMMVersion.value return latestTRMMVersion.value
@@ -180,6 +231,26 @@ export default {
}).onOk(() => store.dispatch("getDashInfo")); }).onOk(() => store.dispatch("getDashInfo"));
} }
function resetPassword() {
$q.dialog({
component: ResetPass,
});
}
function reset2FA() {
$q.dialog({
title: "Reset 2FA",
message: "Are you sure you would like to reset your 2FA token?",
cancel: true,
persistent: true,
}).onOk(async () => {
try {
const ret = await resetTwoFactor();
notifySuccess(ret, 3000);
} catch {}
});
}
const serverCount = ref(0); const serverCount = ref(0);
const serverOfflineCount = ref(0); const serverOfflineCount = ref(0);
const workstationCount = ref(0); const workstationCount = ref(0);
@@ -259,9 +330,13 @@ export default {
user, user,
needRefresh, needRefresh,
darkMode, darkMode,
hosted,
tokenExpired,
// methods // methods
showUserPreferences, showUserPreferences,
resetPassword,
reset2FA,
updateAvailable, updateAvailable,
}; };
}, },

View File

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

View File

@@ -17,6 +17,7 @@ export default function () {
agentPlatform: "windows", agentPlatform: "windows",
agentTableLoading: false, agentTableLoading: false,
needrefresh: false, needrefresh: false,
tokenExpired: false,
refreshSummaryTab: false, refreshSummaryTab: false,
tableHeight: "300px", tableHeight: "300px",
tabHeight: "300px", tabHeight: "300px",
@@ -83,6 +84,9 @@ export default function () {
SET_REFRESH_NEEDED(state, action) { SET_REFRESH_NEEDED(state, action) {
state.needrefresh = action; state.needrefresh = action;
}, },
SET_TOKEN_EXPIRED(state, action) {
state.tokenExpired = action;
},
SET_SPLITTER(state, val) { SET_SPLITTER(state, val) {
// top toolbar is 50px. Filebar is 40px and agent filter tabs are 44px // top toolbar is 50px. Filebar is 40px and agent filter tabs are 44px
state.tableHeight = `${Screen.height - 50 - 40 - 78 - val}px`; state.tableHeight = `${Screen.height - 50 - 40 - 78 - val}px`;
@@ -212,6 +216,7 @@ export default function () {
context.commit("SET_URL_ACTION", data.url_action); context.commit("SET_URL_ACTION", data.url_action);
context.commit("setShowCommunityScripts", data.show_community_scripts); context.commit("setShowCommunityScripts", data.show_community_scripts);
context.commit("SET_HOSTED", data.hosted); context.commit("SET_HOSTED", data.hosted);
context.commit("SET_TOKEN_EXPIRED", data.token_is_expired);
if (data.date_format && data.date_format !== "") if (data.date_format && data.date_format !== "")
context.commit("setDateFormat", data.date_format); context.commit("setDateFormat", data.date_format);

View File

@@ -68,6 +68,7 @@ export function formatScriptOptions(data) {
value: script.id, value: script.id,
timeout: script.default_timeout, timeout: script.default_timeout,
args: script.args, args: script.args,
env_vars: script.env_vars,
filename: script.filename, filename: script.filename,
syntax: script.syntax, syntax: script.syntax,
script_type: script.script_type, script_type: script.script_type,
@@ -80,6 +81,7 @@ export function formatScriptOptions(data) {
value: script.id, value: script.id,
timeout: script.default_timeout, timeout: script.default_timeout,
args: script.args, args: script.args,
env_vars: script.env_vars,
filename: script.filename, filename: script.filename,
syntax: script.syntax, syntax: script.syntax,
script_type: script.script_type, script_type: script.script_type,

View File

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