Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
13f0f117da | ||
|
|
2db4eeec05 | ||
|
|
fe5e8aa5fe | ||
|
|
13e35d24a2 | ||
|
|
0b6ae80777 | ||
|
|
5e0fab88a3 | ||
|
|
bf8797264b | ||
|
|
14bde967bd | ||
|
|
596ce69789 | ||
|
|
c5491dcb73 | ||
|
|
3f6340f0a1 | ||
|
|
351f0870a9 | ||
|
|
f2638a4c5e | ||
|
|
2bd00d5ca0 | ||
|
|
00a40dd450 | ||
|
|
cfe1cb2dbf | ||
|
|
16fb75b56c | ||
|
|
094cf45ce3 | ||
|
|
d6984b3da9 | ||
|
|
53fc6f4cde | ||
|
|
e1dc8050e3 | ||
|
|
49da10cf0b | ||
|
|
a3e10910bf | ||
|
|
3ff9edc424 | ||
|
|
69414d4083 | ||
|
|
e06b7a7775 | ||
|
|
c006e4d922 | ||
|
|
df6fe0863b | ||
|
|
d55a29911c | ||
|
|
d0e49d27fd | ||
|
|
1299bfc93e | ||
|
|
be999646d4 | ||
|
|
e57d32f122 | ||
|
|
3e6365574e | ||
|
|
08fa8da735 | ||
|
|
4ab31a529e | ||
|
|
466725d5c2 |
@@ -1,9 +1,9 @@
|
||||
version: '3.4'
|
||||
version: '3.7'
|
||||
|
||||
services:
|
||||
app-dev:
|
||||
container_name: trmm-app-dev
|
||||
image: node:16-alpine
|
||||
image: node:18-alpine
|
||||
restart: always
|
||||
command: /bin/sh -c "npm install --cache ~/.npm && npm run serve"
|
||||
user: 1000:1000
|
||||
|
||||
774
package-lock.json
generated
774
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
40
package.json
40
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "web",
|
||||
"version": "0.101.35",
|
||||
"version": "0.101.40",
|
||||
"private": true,
|
||||
"productName": "Tactical RMM",
|
||||
"scripts": {
|
||||
@@ -10,34 +10,34 @@
|
||||
"format": "prettier --write \"**/*.{js,ts,vue,,html,md,json}\" --ignore-path .gitignore"
|
||||
},
|
||||
"dependencies": {
|
||||
"@quasar/extras": "1.16.7",
|
||||
"apexcharts": "3.44.0",
|
||||
"axios": "1.6.0",
|
||||
"dotenv": "16.3.1",
|
||||
"@quasar/extras": "1.16.9",
|
||||
"apexcharts": "3.45.2",
|
||||
"axios": "1.6.7",
|
||||
"dotenv": "16.4.1",
|
||||
"qrcode.vue": "3.4.1",
|
||||
"quasar": "2.13.0",
|
||||
"vue": "3.3.8",
|
||||
"quasar": "2.14.3",
|
||||
"vue": "3.4.15",
|
||||
"vue3-apexcharts": "1.4.4",
|
||||
"vuedraggable": "4.1.0",
|
||||
"vue-router": "4.2.5",
|
||||
"@vueuse/core": "10.5.0",
|
||||
"@vueuse/shared": "10.5.0",
|
||||
"monaco-editor": "0.44.0",
|
||||
"@vueuse/core": "10.7.2",
|
||||
"@vueuse/shared": "10.7.2",
|
||||
"monaco-editor": "0.45.0",
|
||||
"vuex": "4.1.0",
|
||||
"yaml": "2.3.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@quasar/cli": "2.3.0",
|
||||
"@intlify/unplugin-vue-i18n": "1.4.0",
|
||||
"@quasar/app-vite": "1.6.2",
|
||||
"@types/node": "20.8.10",
|
||||
"@typescript-eslint/eslint-plugin": "6.10.0",
|
||||
"@typescript-eslint/parser": "6.10.0",
|
||||
"autoprefixer": "10.4.16",
|
||||
"eslint": "8.53.0",
|
||||
"eslint-config-prettier": "9.0.0",
|
||||
"@intlify/unplugin-vue-i18n": "2.0.0",
|
||||
"@quasar/app-vite": "1.7.3",
|
||||
"@types/node": "20.11.6",
|
||||
"@typescript-eslint/eslint-plugin": "6.19.1",
|
||||
"@typescript-eslint/parser": "6.19.1",
|
||||
"autoprefixer": "10.4.17",
|
||||
"eslint": "8.56.0",
|
||||
"eslint-config-prettier": "9.1.0",
|
||||
"eslint-plugin-vue": "8.7.1",
|
||||
"prettier": "3.0.3",
|
||||
"typescript": "5.2.2"
|
||||
"prettier": "3.2.4",
|
||||
"typescript": "5.3.3"
|
||||
}
|
||||
}
|
||||
|
||||
BIN
src/assets/trmm_256.png
Normal file
BIN
src/assets/trmm_256.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@@ -85,10 +85,6 @@
|
||||
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"
|
||||
@@ -447,7 +443,6 @@ export default {
|
||||
can_uninstall_agents: false,
|
||||
can_update_agents: false,
|
||||
can_edit_agent: false,
|
||||
can_ping_agents: false,
|
||||
can_manage_procs: false,
|
||||
can_view_eventlogs: false,
|
||||
can_send_cmd: false,
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
:color="dash_warning_color"
|
||||
class="q-mr-sm"
|
||||
>
|
||||
<q-tooltip>Agent offline</q-tooltip>
|
||||
<q-tooltip>{{ store.getters.formatDate(summary.last_seen) }}</q-tooltip>
|
||||
</q-icon>
|
||||
<q-icon
|
||||
v-else
|
||||
@@ -43,7 +43,7 @@
|
||||
:color="dash_positive_color"
|
||||
class="q-mr-sm"
|
||||
>
|
||||
<q-tooltip>Agent online</q-tooltip>
|
||||
<q-tooltip>{{ store.getters.formatDate(summary.last_seen) }}</q-tooltip>
|
||||
</q-icon>
|
||||
<b>{{ summary.hostname }}</b>
|
||||
<span v-if="summary.maintenance_mode">
|
||||
@@ -267,7 +267,11 @@ export default {
|
||||
const loading = ref(false);
|
||||
|
||||
const serial_number = computed(() => {
|
||||
return summary.value.wmi_detail.bios?.[0]?.[0]?.SerialNumber;
|
||||
if (summary.value.plat === "windows") {
|
||||
return summary.value.wmi_detail.bios?.[0]?.[0]?.SerialNumber;
|
||||
} else {
|
||||
return summary.value.wmi_detail.serialnumber;
|
||||
}
|
||||
});
|
||||
|
||||
const cpu = computed(() => {
|
||||
@@ -280,7 +284,7 @@ export default {
|
||||
function diskBarColor(percent) {
|
||||
if (percent < 80) {
|
||||
return dash_positive_color.value;
|
||||
} else if (percent > 80 && percent < 95) {
|
||||
} else if (percent >= 80 && percent < 95) {
|
||||
return dash_warning_color.value;
|
||||
} else {
|
||||
return dash_negative_color.value;
|
||||
@@ -311,11 +315,11 @@ export default {
|
||||
const ret = [];
|
||||
for (const customField of summary.value.custom_fields) {
|
||||
const definition = customFieldsDefinitions.value.find(
|
||||
(def) => def.id === customField.field
|
||||
(def) => def.id === customField.field,
|
||||
);
|
||||
if (
|
||||
definition &&
|
||||
!definition.hide_in_ui &&
|
||||
!definition.hide_in_summary &&
|
||||
customField.value?.length > 0
|
||||
) {
|
||||
ret.push({
|
||||
@@ -381,6 +385,7 @@ export default {
|
||||
dash_negative_color,
|
||||
serial_number,
|
||||
cpu,
|
||||
store,
|
||||
|
||||
// methods
|
||||
getSummary,
|
||||
|
||||
@@ -254,7 +254,7 @@ export default {
|
||||
pagination: {
|
||||
rowsPerPage: 0,
|
||||
sortBy: "name",
|
||||
descending: true,
|
||||
descending: false,
|
||||
},
|
||||
};
|
||||
},
|
||||
@@ -321,7 +321,7 @@ export default {
|
||||
runTask(task) {
|
||||
if (!task.enabled) {
|
||||
this.notifyError(
|
||||
"Task cannot be run when it's disabled. Enable it first."
|
||||
"Task cannot be run when it's disabled. Enable it first.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<q-dialog ref="dialog" @hide="onHide">
|
||||
<q-card class="q-dialog-plugin" style="width: 90vw">
|
||||
<q-card class="q-dialog-plugin" style="min-width: 70vw">
|
||||
<q-bar>
|
||||
{{ title.slice(0, 27) }}
|
||||
<q-space />
|
||||
|
||||
@@ -137,7 +137,7 @@
|
||||
<q-radio
|
||||
v-model="goarch"
|
||||
:val="GOARCH_ARM64"
|
||||
label="Apple Silicon (M1, M2)"
|
||||
label="Apple Silicon (M1, M2, M3)"
|
||||
v-show="agentOS === 'darwin'"
|
||||
/>
|
||||
<q-radio
|
||||
|
||||
@@ -142,6 +142,11 @@
|
||||
v-model="localField.hide_in_ui"
|
||||
color="green"
|
||||
/>
|
||||
<q-toggle
|
||||
label="Hide in Summary Tab"
|
||||
v-model="localField.hide_in_summary"
|
||||
color="green"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-actions align="right">
|
||||
<q-btn flat label="Cancel" v-close-popup />
|
||||
@@ -172,6 +177,7 @@ export default {
|
||||
default_value_bool: false,
|
||||
default_values_multiple: [],
|
||||
hide_in_ui: false,
|
||||
hide_in_summary: false,
|
||||
},
|
||||
modelOptions: [
|
||||
{ label: "Client", value: "client" },
|
||||
|
||||
@@ -57,6 +57,10 @@
|
||||
<q-td>
|
||||
<q-icon v-if="props.row.hide_in_ui" name="check" />
|
||||
</q-td>
|
||||
<!-- hide in summary tab -->
|
||||
<q-td>
|
||||
<q-icon v-if="props.row.hide_in_summary" name="check" />
|
||||
</q-td>
|
||||
<!-- default value -->
|
||||
<q-td v-if="props.row.type === 'checkbox'">
|
||||
{{ props.row.default_value_bool }}
|
||||
@@ -123,6 +127,13 @@ export default {
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "hide_in_summary",
|
||||
label: "Hide in Summary Tab",
|
||||
field: "hide_in_summary",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "default_value",
|
||||
label: "Default Value",
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
icon="info"
|
||||
@click="
|
||||
openURL(
|
||||
'https://quasar.dev/quasar-utils/date-utils#format-for-display'
|
||||
'https://quasar.dev/quasar-utils/date-utils#format-for-display',
|
||||
)
|
||||
"
|
||||
>
|
||||
@@ -216,7 +216,7 @@
|
||||
<div class="text-subtitle2">SMTP Settings</div>
|
||||
<q-separator />
|
||||
<q-card-section class="row">
|
||||
<div class="col-2">From:</div>
|
||||
<div class="col-2">From email:</div>
|
||||
<div class="col-4"></div>
|
||||
<q-input
|
||||
outlined
|
||||
@@ -226,6 +226,16 @@
|
||||
:rules="[(val) => isValidEmail(val) || 'Invalid email']"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section class="row">
|
||||
<div class="col-2">From name:</div>
|
||||
<div class="col-4"></div>
|
||||
<q-input
|
||||
outlined
|
||||
dense
|
||||
v-model="settings.smtp_from_name"
|
||||
class="col-6 q-pa-none"
|
||||
/>
|
||||
</q-card-section>
|
||||
<q-card-section class="row">
|
||||
<div class="col-2">Host:</div>
|
||||
<div class="col-4"></div>
|
||||
@@ -711,13 +721,13 @@ export default {
|
||||
},
|
||||
removeEmail(email) {
|
||||
const removed = this.settings.email_alert_recipients.filter(
|
||||
(k) => k !== email
|
||||
(k) => k !== email,
|
||||
);
|
||||
this.settings.email_alert_recipients = removed;
|
||||
},
|
||||
removeSMSNumber(num) {
|
||||
const removed = this.settings.sms_alert_recipients.filter(
|
||||
(k) => k !== num
|
||||
(k) => k !== num,
|
||||
);
|
||||
this.settings.sms_alert_recipients = removed;
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<q-dialog ref="dialog" @hide="onHide">
|
||||
<q-card class="q-dialog-plugin" style="min-width: 85vh">
|
||||
<q-card class="q-dialog-plugin" style="min-width: 60vw">
|
||||
<q-splitter v-model="splitterModel">
|
||||
<template v-slot:before>
|
||||
<q-tabs dense v-model="tab" vertical class="text-primary">
|
||||
@@ -201,7 +201,7 @@
|
||||
icon="info"
|
||||
@click="
|
||||
openURL(
|
||||
'https://quasar.dev/quasar-utils/date-utils#format-for-display'
|
||||
'https://quasar.dev/quasar-utils/date-utils#format-for-display',
|
||||
)
|
||||
"
|
||||
>
|
||||
@@ -315,7 +315,7 @@ export default {
|
||||
this.$axios.get("/core/urlaction/").then((r) => {
|
||||
if (r.data.length === 0) {
|
||||
this.notifyWarning(
|
||||
"No URL Actions configured. Go to Settings > Global Settings > URL Actions"
|
||||
"No URL Actions configured. Go to Settings > Global Settings > URL Actions",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
<q-dialog
|
||||
ref="dialogRef"
|
||||
maximized
|
||||
no-esc-dismiss
|
||||
@hide="onDialogHide"
|
||||
@show="loadEditor"
|
||||
@before-hide="unloadEditor"
|
||||
@keydown.esc.stop="closeEditor"
|
||||
>
|
||||
<q-card class="q-dialog-plugin">
|
||||
<q-bar>
|
||||
@@ -20,7 +22,7 @@
|
||||
@click="generateScriptOpenAI"
|
||||
/>
|
||||
<q-space />
|
||||
<q-btn dense flat icon="close" v-close-popup>
|
||||
<q-btn dense flat icon="close" @click="closeEditor">
|
||||
<q-tooltip class="bg-white text-primary">Close</q-tooltip>
|
||||
</q-btn>
|
||||
</q-bar>
|
||||
@@ -190,7 +192,7 @@
|
||||
</template>
|
||||
</tactical-dropdown>
|
||||
<q-space />
|
||||
<q-btn dense flat label="Cancel" v-close-popup />
|
||||
<q-btn dense flat label="Cancel" @click="closeEditor" />
|
||||
<q-btn
|
||||
v-if="!readonly"
|
||||
:loading="loading"
|
||||
@@ -363,7 +365,23 @@ function loadEditor() {
|
||||
downloadScript(script.id, { with_snippets: props.readonly }).then((r) => {
|
||||
script.script_body = r.code;
|
||||
editor.setValue(r.code);
|
||||
|
||||
// need to add this in the download function otherwise the above will trigger an edit
|
||||
watch(
|
||||
() => script.script_body,
|
||||
() => {
|
||||
edited.value = true;
|
||||
},
|
||||
);
|
||||
});
|
||||
else {
|
||||
watch(
|
||||
() => script.script_body,
|
||||
() => {
|
||||
edited.value = true;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// watch for changes in language
|
||||
watch(lang, () => {
|
||||
@@ -394,6 +412,21 @@ function generateScriptOpenAI() {
|
||||
});
|
||||
}
|
||||
|
||||
// add are you sure prompt to unsaved script
|
||||
const edited = ref(false);
|
||||
|
||||
function closeEditor() {
|
||||
if (edited.value)
|
||||
$q.dialog({
|
||||
title: "You have unsaved changes. Are you sure you want to close?",
|
||||
cancel: true,
|
||||
ok: true,
|
||||
}).onOk(async () => {
|
||||
unloadEditor();
|
||||
});
|
||||
else unloadEditor();
|
||||
}
|
||||
|
||||
// component life cycle hooks
|
||||
onMounted(async () => {
|
||||
agentLoading.value = true;
|
||||
|
||||
@@ -176,6 +176,14 @@
|
||||
<q-tooltip> Shell </q-tooltip>
|
||||
</q-icon>
|
||||
|
||||
<!-- is community script icon -->
|
||||
<img
|
||||
v-if="props.node.script_type === 'builtin'"
|
||||
class="vertical-middle"
|
||||
:src="trmmLogo"
|
||||
style="height: 20px; max-width: 20px"
|
||||
/>
|
||||
|
||||
<span
|
||||
class="q-pl-xs text-weight-bold"
|
||||
:style="{ color: props.node.hidden ? 'grey' : '' }"
|
||||
@@ -488,6 +496,12 @@
|
||||
:props="props"
|
||||
:style="{ color: props.row.hidden ? 'grey' : '' }"
|
||||
>
|
||||
<!-- is community script icon -->
|
||||
<img
|
||||
v-if="props.row.script_type === 'builtin'"
|
||||
:src="trmmLogo"
|
||||
style="height: 20px; max-width: 20px"
|
||||
/>
|
||||
{{ truncateText(props.row.name, 50) }}
|
||||
<q-tooltip
|
||||
v-if="props.row.name.length >= 50"
|
||||
@@ -550,6 +564,8 @@ import ScriptFormModal from "@/components/scripts/ScriptFormModal.vue";
|
||||
import ScriptSnippets from "@/components/scripts/ScriptSnippets.vue";
|
||||
import TacticalTable from "@/components/ui/TacticalTable.vue";
|
||||
|
||||
import trmmLogo from "@/assets/trmm_256.png";
|
||||
|
||||
// static data
|
||||
const columns = [
|
||||
{
|
||||
@@ -620,7 +636,7 @@ export default {
|
||||
// setup vuex store
|
||||
const store = useStore();
|
||||
const showCommunityScripts = computed(
|
||||
() => store.state.showCommunityScripts
|
||||
() => store.state.showCommunityScripts,
|
||||
);
|
||||
|
||||
// setup quasar plugins
|
||||
@@ -721,7 +737,7 @@ export default {
|
||||
return showCommunityScripts.value
|
||||
? scripts.value.filter((i) => !i.hidden)
|
||||
: scripts.value.filter(
|
||||
(i) => i.script_type !== "builtin" && !i.hidden
|
||||
(i) => i.script_type !== "builtin" && !i.hidden,
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -884,6 +900,7 @@ export default {
|
||||
loading,
|
||||
showCommunityScripts,
|
||||
showHiddenScripts,
|
||||
trmmLogo,
|
||||
|
||||
// computed
|
||||
visibleScripts,
|
||||
|
||||
@@ -8,8 +8,25 @@
|
||||
<q-tooltip class="bg-white text-primary">Close</q-tooltip>
|
||||
</q-btn>
|
||||
</q-bar>
|
||||
<q-card-section class="scroll" style="max-height: 70vh; height: 70vh">
|
||||
<pre v-if="ret">{{ ret }}</pre>
|
||||
<q-card-section style="height: 70vh" class="scroll">
|
||||
<div>
|
||||
Run Time:
|
||||
<code>{{ ret.execution_time }} seconds</code>
|
||||
<br />Return Code:
|
||||
<code>{{ ret.retcode }}</code>
|
||||
<br />
|
||||
</div>
|
||||
<br />
|
||||
<div v-if="ret.stdout">
|
||||
Standard Output
|
||||
<q-separator />
|
||||
<pre>{{ ret.stdout }}</pre>
|
||||
</div>
|
||||
<div v-if="ret.stderr">
|
||||
Standard Error
|
||||
<q-separator />
|
||||
<pre>{{ ret.stderr }}</pre>
|
||||
</div>
|
||||
<q-inner-loading :showing="loading" />
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
@@ -34,7 +51,12 @@ export default {
|
||||
const { dialogRef, onDialogHide } = useDialogPluginComponent();
|
||||
|
||||
// main run script functionality
|
||||
const ret = ref(null);
|
||||
const ret = ref({
|
||||
execution_time: "",
|
||||
retcode: "",
|
||||
stdout: "",
|
||||
stderr: "",
|
||||
});
|
||||
const loading = ref(false);
|
||||
|
||||
async function runTestScript() {
|
||||
|
||||
@@ -87,181 +87,183 @@
|
||||
:done="step > 2"
|
||||
:error="!isValidStep2"
|
||||
>
|
||||
<q-form @submit.prevent="addAction">
|
||||
<div class="row q-pa-sm q-gutter-x-xs items-center">
|
||||
<div class="text-subtitle2 col-12">Action Type:</div>
|
||||
<q-option-group
|
||||
class="col-12"
|
||||
inline
|
||||
v-model="actionType"
|
||||
:options="[
|
||||
{ label: 'Script', value: 'script' },
|
||||
{ label: 'Command', value: 'cmd' },
|
||||
]"
|
||||
/>
|
||||
<div class="scroll" style="max-height: 60vh">
|
||||
<q-form @submit.prevent="addAction">
|
||||
<div class="row q-pa-sm q-gutter-x-xs items-center">
|
||||
<div class="text-subtitle2 col-12">Action Type:</div>
|
||||
<q-option-group
|
||||
class="col-12"
|
||||
inline
|
||||
v-model="actionType"
|
||||
:options="[
|
||||
{ label: 'Script', value: 'script' },
|
||||
{ label: 'Command', value: 'cmd' },
|
||||
]"
|
||||
/>
|
||||
|
||||
<tactical-dropdown
|
||||
v-if="actionType === 'script'"
|
||||
class="col-3"
|
||||
label="Select script"
|
||||
v-model="script"
|
||||
:options="scriptOptions"
|
||||
filled
|
||||
mapOptions
|
||||
filterable
|
||||
/>
|
||||
<tactical-dropdown
|
||||
v-if="actionType === 'script'"
|
||||
class="col-3"
|
||||
label="Select script"
|
||||
v-model="script"
|
||||
:options="scriptOptions"
|
||||
filled
|
||||
mapOptions
|
||||
filterable
|
||||
/>
|
||||
|
||||
<q-select
|
||||
v-if="actionType === 'script'"
|
||||
class="col-3"
|
||||
dense
|
||||
label="Script Arguments (press Enter after typing each argument)"
|
||||
filled
|
||||
v-model="defaultArgs"
|
||||
use-input
|
||||
use-chips
|
||||
multiple
|
||||
hide-dropdown-icon
|
||||
input-debounce="0"
|
||||
new-value-mode="add"
|
||||
/>
|
||||
<q-select
|
||||
v-if="actionType === 'script'"
|
||||
class="col-3"
|
||||
dense
|
||||
label="Script Arguments (press Enter after typing each argument)"
|
||||
filled
|
||||
v-model="defaultArgs"
|
||||
use-input
|
||||
use-chips
|
||||
multiple
|
||||
hide-dropdown-icon
|
||||
input-debounce="0"
|
||||
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-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
|
||||
v-if="actionType === 'script'"
|
||||
class="col-2"
|
||||
filled
|
||||
dense
|
||||
v-model.number="defaultTimeout"
|
||||
type="number"
|
||||
label="Timeout (seconds)"
|
||||
/>
|
||||
<q-input
|
||||
v-if="actionType === 'script'"
|
||||
class="col-2"
|
||||
filled
|
||||
dense
|
||||
v-model.number="defaultTimeout"
|
||||
type="number"
|
||||
label="Timeout (seconds)"
|
||||
/>
|
||||
|
||||
<q-input
|
||||
v-if="actionType === 'cmd'"
|
||||
label="Command"
|
||||
v-model="command"
|
||||
<q-input
|
||||
v-if="actionType === 'cmd'"
|
||||
label="Command"
|
||||
v-model="command"
|
||||
dense
|
||||
filled
|
||||
class="col-7"
|
||||
/>
|
||||
<q-input
|
||||
v-if="actionType === 'cmd'"
|
||||
class="col-2"
|
||||
filled
|
||||
dense
|
||||
v-model.number="defaultTimeout"
|
||||
type="number"
|
||||
label="Timeout (seconds)"
|
||||
/>
|
||||
<q-option-group
|
||||
v-if="actionType === 'cmd'"
|
||||
class="col-2 q-pl-sm"
|
||||
inline
|
||||
v-model="shell"
|
||||
:options="[
|
||||
{ label: 'Batch', value: 'cmd' },
|
||||
{ label: 'Powershell', value: 'powershell' },
|
||||
]"
|
||||
/>
|
||||
<q-btn
|
||||
class="col-1"
|
||||
type="submit"
|
||||
style="width: 50px"
|
||||
flat
|
||||
dense
|
||||
icon="add"
|
||||
color="primary"
|
||||
/>
|
||||
</div>
|
||||
</q-form>
|
||||
<div class="text-subtitle2 q-pa-sm">
|
||||
Actions:
|
||||
<q-checkbox
|
||||
class="float-right"
|
||||
label="Continue on Errors"
|
||||
v-model="state.continue_on_error"
|
||||
dense
|
||||
filled
|
||||
class="col-7"
|
||||
/>
|
||||
<q-input
|
||||
v-if="actionType === 'cmd'"
|
||||
class="col-2"
|
||||
filled
|
||||
dense
|
||||
v-model.number="defaultTimeout"
|
||||
type="number"
|
||||
label="Timeout (seconds)"
|
||||
/>
|
||||
<q-option-group
|
||||
v-if="actionType === 'cmd'"
|
||||
class="col-2 q-pl-sm"
|
||||
inline
|
||||
v-model="shell"
|
||||
:options="[
|
||||
{ label: 'Batch', value: 'cmd' },
|
||||
{ label: 'Powershell', value: 'powershell' },
|
||||
]"
|
||||
/>
|
||||
<q-btn
|
||||
class="col-1"
|
||||
type="submit"
|
||||
style="width: 50px"
|
||||
flat
|
||||
dense
|
||||
icon="add"
|
||||
color="primary"
|
||||
/>
|
||||
>
|
||||
<q-tooltip>Continue task if an action fails</q-tooltip>
|
||||
</q-checkbox>
|
||||
</div>
|
||||
</q-form>
|
||||
<div class="text-subtitle2 q-pa-sm">
|
||||
Actions:
|
||||
<q-checkbox
|
||||
class="float-right"
|
||||
label="Continue on Errors"
|
||||
v-model="state.continue_on_error"
|
||||
dense
|
||||
>
|
||||
<q-tooltip>Continue task if an action fails</q-tooltip>
|
||||
</q-checkbox>
|
||||
</div>
|
||||
<div class="scroll q-pt-sm" style="height: 40vh; max-height: 40vh">
|
||||
<draggable
|
||||
class="q-list"
|
||||
handle=".handle"
|
||||
ghost-class="ghost"
|
||||
v-model="state.actions"
|
||||
item-key="index"
|
||||
>
|
||||
<template v-slot:item="{ index, element }">
|
||||
<q-item>
|
||||
<q-item-section avatar>
|
||||
<q-icon
|
||||
class="handle"
|
||||
style="cursor: move"
|
||||
name="drag_handle"
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section v-if="element.type === 'script'">
|
||||
<q-item-label>
|
||||
<q-icon size="sm" name="description" color="primary" />
|
||||
{{ element.name }}
|
||||
</q-item-label>
|
||||
<q-item-label caption>
|
||||
Arguments: {{ element.script_args }}
|
||||
</q-item-label>
|
||||
<q-item-label caption>
|
||||
Env Vars: {{ element.env_vars }}
|
||||
</q-item-label>
|
||||
<q-item-label caption>
|
||||
Timeout: {{ element.timeout }}
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section v-else>
|
||||
<q-item-label>
|
||||
<q-icon size="sm" name="terminal" color="primary" />
|
||||
|
||||
<div class="q-pt-sm" style="height: 150px">
|
||||
<draggable
|
||||
class="q-list"
|
||||
handle=".handle"
|
||||
ghost-class="ghost"
|
||||
v-model="state.actions"
|
||||
item-key="index"
|
||||
>
|
||||
<template v-slot:item="{ index, element }">
|
||||
<q-item>
|
||||
<q-item-section avatar>
|
||||
<q-icon
|
||||
size="sm"
|
||||
:name="
|
||||
element.shell === 'cmd'
|
||||
? 'mdi-microsoft-windows'
|
||||
: 'mdi-powershell'
|
||||
"
|
||||
color="primary"
|
||||
class="handle"
|
||||
style="cursor: move"
|
||||
name="drag_handle"
|
||||
/>
|
||||
{{ element.command }}
|
||||
</q-item-label>
|
||||
<q-item-label caption>
|
||||
Timeout: {{ element.timeout }}
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section side>
|
||||
<q-icon
|
||||
class="cursor-pointer"
|
||||
color="negative"
|
||||
name="close"
|
||||
@click="removeAction(index)"
|
||||
/>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</template>
|
||||
</draggable>
|
||||
</q-item-section>
|
||||
<q-item-section v-if="element.type === 'script'">
|
||||
<q-item-label>
|
||||
<q-icon size="sm" name="description" color="primary" />
|
||||
{{ element.name }}
|
||||
</q-item-label>
|
||||
<q-item-label caption>
|
||||
Arguments: {{ element.script_args }}
|
||||
</q-item-label>
|
||||
<q-item-label caption>
|
||||
Env Vars: {{ element.env_vars }}
|
||||
</q-item-label>
|
||||
<q-item-label caption>
|
||||
Timeout: {{ element.timeout }}
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section v-else>
|
||||
<q-item-label>
|
||||
<q-icon size="sm" name="terminal" color="primary" />
|
||||
|
||||
<q-icon
|
||||
size="sm"
|
||||
:name="
|
||||
element.shell === 'cmd'
|
||||
? 'mdi-microsoft-windows'
|
||||
: 'mdi-powershell'
|
||||
"
|
||||
color="primary"
|
||||
/>
|
||||
{{ element.command }}
|
||||
</q-item-label>
|
||||
<q-item-label caption>
|
||||
Timeout: {{ element.timeout }}
|
||||
</q-item-label>
|
||||
</q-item-section>
|
||||
<q-item-section side>
|
||||
<q-icon
|
||||
class="cursor-pointer"
|
||||
color="negative"
|
||||
name="close"
|
||||
@click="removeAction(index)"
|
||||
/>
|
||||
</q-item-section>
|
||||
</q-item>
|
||||
</template>
|
||||
</draggable>
|
||||
</div>
|
||||
</div>
|
||||
</q-step>
|
||||
|
||||
@@ -283,7 +285,7 @@
|
||||
<q-card-section
|
||||
v-if="
|
||||
['runonce', 'daily', 'weekly', 'monthly'].includes(
|
||||
state.task_type
|
||||
state.task_type,
|
||||
)
|
||||
"
|
||||
class="row"
|
||||
@@ -314,6 +316,22 @@
|
||||
/>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-section
|
||||
v-if="
|
||||
state.task_type === 'onboarding' ||
|
||||
state.task_type === 'runonce'
|
||||
"
|
||||
class="row"
|
||||
>
|
||||
<span v-if="state.task_type === 'onboarding'"
|
||||
>This task will run as soon as it's created on the
|
||||
agent.</span
|
||||
>
|
||||
<span v-else-if="state.task_type === 'runonce'"
|
||||
>Start Time must be in the future for run once tasks.</span
|
||||
>
|
||||
</q-card-section>
|
||||
|
||||
<!-- daily options -->
|
||||
<q-card-section v-if="state.task_type === 'daily'" class="row">
|
||||
<!-- daily interval -->
|
||||
@@ -579,7 +597,8 @@
|
||||
<q-card-section
|
||||
v-if="
|
||||
state.task_type !== 'checkfailure' &&
|
||||
state.task_type !== 'manual'
|
||||
state.task_type !== 'manual' &&
|
||||
state.task_type !== 'onboarding'
|
||||
"
|
||||
class="row"
|
||||
>
|
||||
@@ -617,7 +636,7 @@
|
||||
(val) =>
|
||||
convertPeriodToSeconds(val) >=
|
||||
convertPeriodToSeconds(
|
||||
state.task_repetition_interval
|
||||
state.task_repetition_interval,
|
||||
) ||
|
||||
'Repetition duration must be greater than repetition interval',
|
||||
]"
|
||||
@@ -712,7 +731,7 @@
|
||||
@click="
|
||||
validateStep(
|
||||
step === 1 ? $refs.taskGeneralForm : undefined,
|
||||
$refs.stepper
|
||||
$refs.stepper,
|
||||
)
|
||||
"
|
||||
color="primary"
|
||||
@@ -769,6 +788,7 @@ const taskTypeOptions = [
|
||||
{ label: "Monthly", value: "monthly" },
|
||||
{ label: "Run Once", value: "runonce" },
|
||||
{ label: "On check failure", value: "checkfailure" },
|
||||
{ label: "Onboarding", value: "onboarding" },
|
||||
{ label: "Manual", value: "manual" },
|
||||
];
|
||||
|
||||
@@ -933,7 +953,7 @@ export default {
|
||||
task.value.actions.push({
|
||||
type: "script",
|
||||
name: scriptOptions.value.find(
|
||||
(option) => option.value === script.value
|
||||
(option) => option.value === script.value,
|
||||
).label,
|
||||
script: script.value,
|
||||
timeout: defaultTimeout.value,
|
||||
@@ -1019,13 +1039,13 @@ export default {
|
||||
// remove milliseconds and Z to work with native date input
|
||||
task.value.run_time_date = formatDateInputField(
|
||||
task.value.run_time_date,
|
||||
true
|
||||
true,
|
||||
);
|
||||
|
||||
if (task.value.expire_date)
|
||||
task.value.expire_date = formatDateInputField(
|
||||
task.value.expire_date,
|
||||
true
|
||||
true,
|
||||
);
|
||||
|
||||
// set task type if monthlydow is being used
|
||||
@@ -1069,7 +1089,7 @@ export default {
|
||||
task.value.monthly_weeks_of_month = [];
|
||||
task.value.task_instance_policy = 0;
|
||||
task.value.expire_date = null;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// check the collector box when editing task and custom field is set
|
||||
|
||||
@@ -25,13 +25,21 @@
|
||||
:key="mapOptions ? scope.opt.value : scope.opt"
|
||||
>
|
||||
<q-item-section>
|
||||
<q-item-label
|
||||
v-html="mapOptions ? scope.opt.label : scope.opt"
|
||||
></q-item-label>
|
||||
<q-item-label v-html="mapOptions ? scope.opt.label : scope.opt" />
|
||||
</q-item-section>
|
||||
<q-item-section
|
||||
v-if="
|
||||
(filtered && mapOptions && scope.opt.cat) || scope.opt.img_right
|
||||
"
|
||||
side
|
||||
>
|
||||
{{ scope.opt.cat || "" }}
|
||||
<img
|
||||
v-if="scope.opt.img_right"
|
||||
:src="scope.opt.img_right"
|
||||
style="height: 20px; max-width: 20px"
|
||||
/>
|
||||
</q-item-section>
|
||||
<q-item-section v-if="filtered && mapOptions && scope.opt.cat" side>{{
|
||||
scope.opt.cat
|
||||
}}</q-item-section>
|
||||
</q-item>
|
||||
<q-item-label
|
||||
v-if="scope.opt.category"
|
||||
@@ -80,7 +88,7 @@ export default {
|
||||
|
||||
if (!props.mapOptions)
|
||||
filteredOptions.value = props.options.filter(
|
||||
(v) => v.toLowerCase().indexOf(needle) > -1
|
||||
(v) => v.toLowerCase().indexOf(needle) > -1,
|
||||
);
|
||||
else
|
||||
filteredOptions.value = props.options.filter((v) => {
|
||||
|
||||
@@ -32,7 +32,7 @@ For details, see: https://license.tacticalrmm.com/ee
|
||||
:rows="reportTemplates"
|
||||
:columns="columns"
|
||||
:loading="isLoading"
|
||||
:pagination="{ rowsPerPage: 0, sortBy: 'name', descending: true }"
|
||||
:pagination="{ rowsPerPage: 0, sortBy: 'name', descending: false }"
|
||||
:filter="search"
|
||||
row-key="id"
|
||||
binary-state-sort
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
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
|
||||
For any issues or to renew your sponsorship please open a ticket at
|
||||
support.amidaware.com<br /><br
|
||||
/></span>
|
||||
<q-btn
|
||||
color="dark"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { date } from "quasar";
|
||||
import { validateTimePeriod } from "@/utils/validation";
|
||||
import trmmLogo from "@/assets/trmm_256.png";
|
||||
// dropdown options formatting
|
||||
|
||||
export function removeExtraOptionCategories(array) {
|
||||
@@ -24,7 +25,7 @@ function _formatOptions(
|
||||
flat = false,
|
||||
allowDuplicates = true,
|
||||
appendToOptionObject = {},
|
||||
}
|
||||
},
|
||||
) {
|
||||
if (!flat)
|
||||
// returns array of options in object format [{label: label, value: 1}]
|
||||
@@ -64,6 +65,7 @@ export function formatScriptOptions(data) {
|
||||
data.forEach((script) => {
|
||||
if (script.category === cat) {
|
||||
tmp.push({
|
||||
img_right: script.script_type === "builtin" ? trmmLogo : undefined,
|
||||
label: script.name,
|
||||
value: script.id,
|
||||
timeout: script.default_timeout,
|
||||
@@ -100,7 +102,7 @@ export function formatScriptOptions(data) {
|
||||
export function formatAgentOptions(
|
||||
data,
|
||||
flat = false,
|
||||
value_field = "agent_id"
|
||||
value_field = "agent_id",
|
||||
) {
|
||||
if (flat) {
|
||||
// returns just agent hostnames in array
|
||||
@@ -185,7 +187,7 @@ export function formatSiteOptions(data, flat = false) {
|
||||
label: "name",
|
||||
flat: flat,
|
||||
appendToOptionObject: { cat: client.name },
|
||||
})
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -361,7 +363,7 @@ export function convertToBitArray(number) {
|
||||
bitArray.push(1);
|
||||
} else {
|
||||
bitArray.push(
|
||||
parseInt(binary.slice(i), 2) - parseInt(binary.slice(i + 1), 2)
|
||||
parseInt(binary.slice(i), 2) - parseInt(binary.slice(i + 1), 2),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
autofocus
|
||||
outlined
|
||||
v-model="credentials.twofactor"
|
||||
autocomplete="one-time-code"
|
||||
:rules="[
|
||||
(val) =>
|
||||
(val && val.length > 0) || 'This field is required',
|
||||
|
||||
Reference in New Issue
Block a user