Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e837c494cb | ||
|
|
afc40fcbe3 | ||
|
|
185f50787b | ||
|
|
6c33676f73 | ||
|
|
0290002444 | ||
|
|
fc5195e817 | ||
|
|
efd5c3dca1 | ||
|
|
2f438feec2 | ||
|
|
07ae9dfddf | ||
|
|
64575c5f7d | ||
|
|
e0fa339644 | ||
|
|
b72a86e514 | ||
|
|
62f0414afa | ||
|
|
200a02b87b | ||
|
|
da5dbeaf0f | ||
|
|
4b6d099f72 | ||
|
|
842661ada6 | ||
|
|
f5148c87c8 | ||
|
|
16164c0bbc | ||
|
|
f38ddb840b | ||
|
|
f86fe26ffe | ||
|
|
162360bf45 | ||
|
|
612aaa7880 | ||
|
|
e91f3fe53d | ||
|
|
f0fe4d64bc | ||
|
|
07cc6aca6a | ||
|
|
23bf81efbb | ||
|
|
a55105e5ee | ||
|
|
5832a426bc | ||
|
|
38dc709108 | ||
|
|
5696d3359b | ||
|
|
1b4fa84753 | ||
|
|
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 | ||
|
|
fe8d88497f | ||
|
|
4ab31a529e | ||
|
|
466725d5c2 |
@@ -1,9 +1,9 @@
|
|||||||
version: '3.4'
|
version: '3.7'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
app-dev:
|
app-dev:
|
||||||
container_name: trmm-app-dev
|
container_name: trmm-app-dev
|
||||||
image: node:16-alpine
|
image: node:18-alpine
|
||||||
restart: always
|
restart: always
|
||||||
command: /bin/sh -c "npm install --cache ~/.npm && npm run serve"
|
command: /bin/sh -c "npm install --cache ~/.npm && npm run serve"
|
||||||
user: 1000:1000
|
user: 1000:1000
|
||||||
|
|||||||
8
.github/workflows/build-release.yml
vendored
8
.github/workflows/build-release.yml
vendored
@@ -11,11 +11,11 @@ jobs:
|
|||||||
name: Build web
|
name: Build web
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: "20.11.1"
|
||||||
|
|
||||||
- run: touch env-config.js
|
- run: touch env-config.js
|
||||||
|
|
||||||
@@ -29,6 +29,6 @@ jobs:
|
|||||||
run: tar -czvf trmm-web-${{github.ref_name}}.tar.gz dist/
|
run: tar -czvf trmm-web-${{github.ref_name}}.tar.gz dist/
|
||||||
|
|
||||||
- name: Release
|
- name: Release
|
||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v2
|
||||||
with:
|
with:
|
||||||
files: trmm-web-${{github.ref_name}}.tar.gz
|
files: trmm-web-${{github.ref_name}}.tar.gz
|
||||||
|
|||||||
1108
package-lock.json
generated
1108
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
51
package.json
51
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "web",
|
"name": "web",
|
||||||
"version": "0.101.35",
|
"version": "0.101.43",
|
||||||
"private": true,
|
"private": true,
|
||||||
"productName": "Tactical RMM",
|
"productName": "Tactical RMM",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -10,34 +10,37 @@
|
|||||||
"format": "prettier --write \"**/*.{js,ts,vue,,html,md,json}\" --ignore-path .gitignore"
|
"format": "prettier --write \"**/*.{js,ts,vue,,html,md,json}\" --ignore-path .gitignore"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@quasar/extras": "1.16.7",
|
"@quasar/extras": "1.16.9",
|
||||||
"apexcharts": "3.44.0",
|
"apexcharts": "3.48.0",
|
||||||
"axios": "1.6.0",
|
"axios": "1.6.8",
|
||||||
"dotenv": "16.3.1",
|
"dotenv": "16.4.5",
|
||||||
|
"pinia": "^2.1.7",
|
||||||
"qrcode.vue": "3.4.1",
|
"qrcode.vue": "3.4.1",
|
||||||
"quasar": "2.13.0",
|
"quasar": "2.15.1",
|
||||||
"vue": "3.3.8",
|
"vue": "3.4.21",
|
||||||
"vue3-apexcharts": "1.4.4",
|
"vue3-apexcharts": "1.5.2",
|
||||||
"vuedraggable": "4.1.0",
|
"vuedraggable": "4.1.0",
|
||||||
"vue-router": "4.2.5",
|
"vue-router": "4.3.0",
|
||||||
"@vueuse/core": "10.5.0",
|
"@vueuse/core": "10.9.0",
|
||||||
"@vueuse/shared": "10.5.0",
|
"@vueuse/shared": "10.9.0",
|
||||||
"monaco-editor": "0.44.0",
|
"monaco-editor": "0.47.0",
|
||||||
"vuex": "4.1.0",
|
"vuex": "4.1.0",
|
||||||
"yaml": "2.3.4"
|
"xterm": "^5.3.0",
|
||||||
|
"xterm-addon-fit": "^0.8.0",
|
||||||
|
"yaml": "2.4.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@quasar/cli": "2.3.0",
|
"@quasar/cli": "2.4.0",
|
||||||
"@intlify/unplugin-vue-i18n": "1.4.0",
|
"@intlify/unplugin-vue-i18n": "3.0.1",
|
||||||
"@quasar/app-vite": "1.6.2",
|
"@quasar/app-vite": "1.8.0",
|
||||||
"@types/node": "20.8.10",
|
"@types/node": "20.11.30",
|
||||||
"@typescript-eslint/eslint-plugin": "6.10.0",
|
"@typescript-eslint/eslint-plugin": "7.3.1",
|
||||||
"@typescript-eslint/parser": "6.10.0",
|
"@typescript-eslint/parser": "7.3.1",
|
||||||
"autoprefixer": "10.4.16",
|
"autoprefixer": "10.4.18",
|
||||||
"eslint": "8.53.0",
|
"eslint": "8.57.0",
|
||||||
"eslint-config-prettier": "9.0.0",
|
"eslint-config-prettier": "9.1.0",
|
||||||
"eslint-plugin-vue": "8.7.1",
|
"eslint-plugin-vue": "8.7.1",
|
||||||
"prettier": "3.0.3",
|
"prettier": "3.2.5",
|
||||||
"typescript": "5.2.2"
|
"typescript": "5.4.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ module.exports = configure(function (/* ctx */) {
|
|||||||
|
|
||||||
// https://github.com/quasarframework/quasar/tree/dev/extras
|
// https://github.com/quasarframework/quasar/tree/dev/extras
|
||||||
extras: [
|
extras: [
|
||||||
// 'ionicons-v4',
|
"ionicons-v4",
|
||||||
"mdi-v5",
|
"mdi-v5",
|
||||||
"fontawesome-v6",
|
"fontawesome-v6",
|
||||||
// 'eva-icons',
|
// 'eva-icons',
|
||||||
@@ -51,8 +51,8 @@ module.exports = configure(function (/* ctx */) {
|
|||||||
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#build
|
// Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#build
|
||||||
build: {
|
build: {
|
||||||
target: {
|
target: {
|
||||||
browser: ["es2021"],
|
browser: ["es2022"],
|
||||||
node: "node16",
|
node: "node20",
|
||||||
},
|
},
|
||||||
|
|
||||||
vueRouterMode: "history", // available values: 'hash', 'history'
|
vueRouterMode: "history", // available values: 'hash', 'history'
|
||||||
|
|||||||
@@ -191,6 +191,11 @@ export async function agentRebootNow(agent_id) {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function agentShutdown(agent_id) {
|
||||||
|
const { data } = await axios.post(`${baseUrl}/${agent_id}/shutdown/`);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
export async function sendAgentRecoverMesh(agent_id, params = {}) {
|
export async function sendAgentRecoverMesh(agent_id, params = {}) {
|
||||||
const { data } = await axios.post(
|
const { data } = await axios.post(
|
||||||
`${baseUrl}/${agent_id}/meshcentral/recover/`,
|
`${baseUrl}/${agent_id}/meshcentral/recover/`,
|
||||||
|
|||||||
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 |
@@ -170,7 +170,7 @@
|
|||||||
overdueAlert(
|
overdueAlert(
|
||||||
'dashboard',
|
'dashboard',
|
||||||
props.row,
|
props.row,
|
||||||
props.row.overdue_dashboard_alert
|
props.row.overdue_dashboard_alert,
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
v-model="props.row.overdue_dashboard_alert"
|
v-model="props.row.overdue_dashboard_alert"
|
||||||
@@ -431,8 +431,8 @@ export default {
|
|||||||
return false;
|
return false;
|
||||||
else if (availability === "expired") {
|
else if (availability === "expired") {
|
||||||
let now = new Date();
|
let now = new Date();
|
||||||
let lastSeen = date.extractDate(row.last_seen, "MM DD YYYY HH:mm");
|
let last_seen_unix = new Date(row.boot_time * 1000);
|
||||||
let diff = date.getDateDiff(now, lastSeen, "days");
|
let diff = date.getDateDiff(now, last_seen_unix, "days");
|
||||||
if (diff < 30) return false;
|
if (diff < 30) return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,10 +85,6 @@
|
|||||||
v-model="localRole.can_uninstall_agents"
|
v-model="localRole.can_uninstall_agents"
|
||||||
label="Uninstall Agents"
|
label="Uninstall Agents"
|
||||||
/>
|
/>
|
||||||
<q-checkbox
|
|
||||||
v-model="localRole.can_ping_agents"
|
|
||||||
label="Ping Agents"
|
|
||||||
/>
|
|
||||||
<q-checkbox
|
<q-checkbox
|
||||||
v-model="localRole.can_update_agents"
|
v-model="localRole.can_update_agents"
|
||||||
label="Update Agents"
|
label="Update Agents"
|
||||||
@@ -111,7 +107,7 @@
|
|||||||
/>
|
/>
|
||||||
<q-checkbox
|
<q-checkbox
|
||||||
v-model="localRole.can_reboot_agents"
|
v-model="localRole.can_reboot_agents"
|
||||||
label="Reboot Agents"
|
label="Shutdown / Reboot Agents"
|
||||||
/>
|
/>
|
||||||
<q-checkbox
|
<q-checkbox
|
||||||
v-model="localRole.can_send_wol"
|
v-model="localRole.can_send_wol"
|
||||||
@@ -447,7 +443,6 @@ export default {
|
|||||||
can_uninstall_agents: false,
|
can_uninstall_agents: false,
|
||||||
can_update_agents: false,
|
can_update_agents: false,
|
||||||
can_edit_agent: false,
|
can_edit_agent: false,
|
||||||
can_ping_agents: false,
|
|
||||||
can_manage_procs: false,
|
can_manage_procs: false,
|
||||||
can_view_eventlogs: false,
|
can_view_eventlogs: false,
|
||||||
can_send_cmd: false,
|
can_send_cmd: false,
|
||||||
|
|||||||
@@ -176,6 +176,13 @@
|
|||||||
</q-menu>
|
</q-menu>
|
||||||
</q-item>
|
</q-item>
|
||||||
|
|
||||||
|
<q-item clickable v-close-popup @click="shutdown(agent)">
|
||||||
|
<q-item-section side>
|
||||||
|
<q-icon size="xs" name="power" />
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section>Shutdown</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
|
||||||
<q-item clickable v-close-popup @click="showPolicyAdd(agent)">
|
<q-item clickable v-close-popup @click="showPolicyAdd(agent)">
|
||||||
<q-item-section side>
|
<q-item-section side>
|
||||||
<q-icon size="xs" name="policy" />
|
<q-icon size="xs" name="policy" />
|
||||||
@@ -192,9 +199,9 @@
|
|||||||
"
|
"
|
||||||
>
|
>
|
||||||
<q-item-section side>
|
<q-item-section side>
|
||||||
<q-icon size="xs" name="integration_instructions" />
|
<q-icon size="xs" name="analytics" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section>Integrations</q-item-section>
|
<q-item-section>Reporting</q-item-section>
|
||||||
<q-item-section side>
|
<q-item-section side>
|
||||||
<q-icon name="keyboard_arrow_right" />
|
<q-icon name="keyboard_arrow_right" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
@@ -231,6 +238,7 @@ import { fetchURLActions, runURLAction } from "@/api/core";
|
|||||||
import {
|
import {
|
||||||
editAgent,
|
editAgent,
|
||||||
agentRebootNow,
|
agentRebootNow,
|
||||||
|
agentShutdown,
|
||||||
sendAgentPing,
|
sendAgentPing,
|
||||||
removeAgent,
|
removeAgent,
|
||||||
runRemoteBackground,
|
runRemoteBackground,
|
||||||
@@ -298,7 +306,7 @@ export default {
|
|||||||
|
|
||||||
if (urlActions.value.length === 0) {
|
if (urlActions.value.length === 0) {
|
||||||
notifyWarning(
|
notifyWarning(
|
||||||
"No URL Actions configured. Go to Settings > Global Settings > URL Actions"
|
"No URL Actions configured. Go to Settings > Global Settings > URL Actions",
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -364,7 +372,7 @@ export default {
|
|||||||
notifySuccess(
|
notifySuccess(
|
||||||
`Maintenance mode was ${
|
`Maintenance mode was ${
|
||||||
agent.maintenance_mode ? "disabled" : "enabled"
|
agent.maintenance_mode ? "disabled" : "enabled"
|
||||||
} on ${agent.hostname}`
|
} on ${agent.hostname}`,
|
||||||
);
|
);
|
||||||
store.commit("setRefreshSummaryTab", true);
|
store.commit("setRefreshSummaryTab", true);
|
||||||
refreshDashboard();
|
refreshDashboard();
|
||||||
@@ -437,6 +445,32 @@ export default {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function shutdown(agent) {
|
||||||
|
$q.dialog({
|
||||||
|
title:
|
||||||
|
'Please type <code style="color:red">yes</code> in the box below to confirm shutdown.',
|
||||||
|
prompt: {
|
||||||
|
model: "",
|
||||||
|
type: "text",
|
||||||
|
isValid: (val) => val === "yes",
|
||||||
|
},
|
||||||
|
cancel: true,
|
||||||
|
ok: { label: "Shutdown", color: "negative" },
|
||||||
|
persistent: true,
|
||||||
|
html: true,
|
||||||
|
}).onOk(async () => {
|
||||||
|
$q.loading.show();
|
||||||
|
try {
|
||||||
|
await agentShutdown(agent.agent_id);
|
||||||
|
notifySuccess(`${agent.hostname} will now be shutdown`);
|
||||||
|
$q.loading.hide();
|
||||||
|
} catch (e) {
|
||||||
|
$q.loading.hide();
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function showPolicyAdd(agent) {
|
function showPolicyAdd(agent) {
|
||||||
$q.dialog({
|
$q.dialog({
|
||||||
component: PolicyAdd,
|
component: PolicyAdd,
|
||||||
@@ -505,7 +539,7 @@ export default {
|
|||||||
notifySuccess(data);
|
notifySuccess(data);
|
||||||
refreshDashboard(
|
refreshDashboard(
|
||||||
false /* clearTreeSelected */,
|
false /* clearTreeSelected */,
|
||||||
true /* clearSubTable */
|
true /* clearSubTable */,
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
@@ -534,6 +568,7 @@ export default {
|
|||||||
runChecks,
|
runChecks,
|
||||||
showRebootLaterModal,
|
showRebootLaterModal,
|
||||||
rebootNow,
|
rebootNow,
|
||||||
|
shutdown,
|
||||||
showPolicyAdd,
|
showPolicyAdd,
|
||||||
showAgentRecovery,
|
showAgentRecovery,
|
||||||
pingAgent,
|
pingAgent,
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
:color="dash_warning_color"
|
:color="dash_warning_color"
|
||||||
class="q-mr-sm"
|
class="q-mr-sm"
|
||||||
>
|
>
|
||||||
<q-tooltip>Agent offline</q-tooltip>
|
<q-tooltip>{{ store.getters.formatDate(summary.last_seen) }}</q-tooltip>
|
||||||
</q-icon>
|
</q-icon>
|
||||||
<q-icon
|
<q-icon
|
||||||
v-else
|
v-else
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
:color="dash_positive_color"
|
:color="dash_positive_color"
|
||||||
class="q-mr-sm"
|
class="q-mr-sm"
|
||||||
>
|
>
|
||||||
<q-tooltip>Agent online</q-tooltip>
|
<q-tooltip>{{ store.getters.formatDate(summary.last_seen) }}</q-tooltip>
|
||||||
</q-icon>
|
</q-icon>
|
||||||
<b>{{ summary.hostname }}</b>
|
<b>{{ summary.hostname }}</b>
|
||||||
<span v-if="summary.maintenance_mode">
|
<span v-if="summary.maintenance_mode">
|
||||||
@@ -267,7 +267,11 @@ export default {
|
|||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|
||||||
const serial_number = computed(() => {
|
const serial_number = computed(() => {
|
||||||
|
if (summary.value.plat === "windows") {
|
||||||
return summary.value.wmi_detail.bios?.[0]?.[0]?.SerialNumber;
|
return summary.value.wmi_detail.bios?.[0]?.[0]?.SerialNumber;
|
||||||
|
} else {
|
||||||
|
return summary.value.wmi_detail.serialnumber;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const cpu = computed(() => {
|
const cpu = computed(() => {
|
||||||
@@ -280,7 +284,7 @@ export default {
|
|||||||
function diskBarColor(percent) {
|
function diskBarColor(percent) {
|
||||||
if (percent < 80) {
|
if (percent < 80) {
|
||||||
return dash_positive_color.value;
|
return dash_positive_color.value;
|
||||||
} else if (percent > 80 && percent < 95) {
|
} else if (percent >= 80 && percent < 95) {
|
||||||
return dash_warning_color.value;
|
return dash_warning_color.value;
|
||||||
} else {
|
} else {
|
||||||
return dash_negative_color.value;
|
return dash_negative_color.value;
|
||||||
@@ -311,11 +315,11 @@ export default {
|
|||||||
const ret = [];
|
const ret = [];
|
||||||
for (const customField of summary.value.custom_fields) {
|
for (const customField of summary.value.custom_fields) {
|
||||||
const definition = customFieldsDefinitions.value.find(
|
const definition = customFieldsDefinitions.value.find(
|
||||||
(def) => def.id === customField.field
|
(def) => def.id === customField.field,
|
||||||
);
|
);
|
||||||
if (
|
if (
|
||||||
definition &&
|
definition &&
|
||||||
!definition.hide_in_ui &&
|
!definition.hide_in_summary &&
|
||||||
customField.value?.length > 0
|
customField.value?.length > 0
|
||||||
) {
|
) {
|
||||||
ret.push({
|
ret.push({
|
||||||
@@ -381,6 +385,7 @@ export default {
|
|||||||
dash_negative_color,
|
dash_negative_color,
|
||||||
serial_number,
|
serial_number,
|
||||||
cpu,
|
cpu,
|
||||||
|
store,
|
||||||
|
|
||||||
// methods
|
// methods
|
||||||
getSummary,
|
getSummary,
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ export default {
|
|||||||
pagination: {
|
pagination: {
|
||||||
rowsPerPage: 0,
|
rowsPerPage: 0,
|
||||||
sortBy: "name",
|
sortBy: "name",
|
||||||
descending: true,
|
descending: false,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -321,7 +321,7 @@ export default {
|
|||||||
runTask(task) {
|
runTask(task) {
|
||||||
if (!task.enabled) {
|
if (!task.enabled) {
|
||||||
this.notifyError(
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-dialog ref="dialog" @hide="onHide">
|
<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>
|
<q-bar>
|
||||||
{{ title.slice(0, 27) }}
|
{{ title.slice(0, 27) }}
|
||||||
<q-space />
|
<q-space />
|
||||||
|
|||||||
@@ -137,7 +137,7 @@
|
|||||||
<q-radio
|
<q-radio
|
||||||
v-model="goarch"
|
v-model="goarch"
|
||||||
:val="GOARCH_ARM64"
|
:val="GOARCH_ARM64"
|
||||||
label="Apple Silicon (M1, M2)"
|
label="Apple Silicon (M1, M2, M3)"
|
||||||
v-show="agentOS === 'darwin'"
|
v-show="agentOS === 'darwin'"
|
||||||
/>
|
/>
|
||||||
<q-radio
|
<q-radio
|
||||||
|
|||||||
@@ -142,6 +142,11 @@
|
|||||||
v-model="localField.hide_in_ui"
|
v-model="localField.hide_in_ui"
|
||||||
color="green"
|
color="green"
|
||||||
/>
|
/>
|
||||||
|
<q-toggle
|
||||||
|
label="Hide in Summary Tab"
|
||||||
|
v-model="localField.hide_in_summary"
|
||||||
|
color="green"
|
||||||
|
/>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-card-actions align="right">
|
<q-card-actions align="right">
|
||||||
<q-btn flat label="Cancel" v-close-popup />
|
<q-btn flat label="Cancel" v-close-popup />
|
||||||
@@ -172,6 +177,7 @@ export default {
|
|||||||
default_value_bool: false,
|
default_value_bool: false,
|
||||||
default_values_multiple: [],
|
default_values_multiple: [],
|
||||||
hide_in_ui: false,
|
hide_in_ui: false,
|
||||||
|
hide_in_summary: false,
|
||||||
},
|
},
|
||||||
modelOptions: [
|
modelOptions: [
|
||||||
{ label: "Client", value: "client" },
|
{ label: "Client", value: "client" },
|
||||||
|
|||||||
@@ -57,6 +57,10 @@
|
|||||||
<q-td>
|
<q-td>
|
||||||
<q-icon v-if="props.row.hide_in_ui" name="check" />
|
<q-icon v-if="props.row.hide_in_ui" name="check" />
|
||||||
</q-td>
|
</q-td>
|
||||||
|
<!-- hide in summary tab -->
|
||||||
|
<q-td>
|
||||||
|
<q-icon v-if="props.row.hide_in_summary" name="check" />
|
||||||
|
</q-td>
|
||||||
<!-- default value -->
|
<!-- default value -->
|
||||||
<q-td v-if="props.row.type === 'checkbox'">
|
<q-td v-if="props.row.type === 'checkbox'">
|
||||||
{{ props.row.default_value_bool }}
|
{{ props.row.default_value_bool }}
|
||||||
@@ -123,6 +127,13 @@ export default {
|
|||||||
align: "left",
|
align: "left",
|
||||||
sortable: true,
|
sortable: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "hide_in_summary",
|
||||||
|
label: "Hide in Summary Tab",
|
||||||
|
field: "hide_in_summary",
|
||||||
|
align: "left",
|
||||||
|
sortable: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "default_value",
|
name: "default_value",
|
||||||
label: "Default Value",
|
label: "Default Value",
|
||||||
|
|||||||
@@ -71,7 +71,7 @@
|
|||||||
icon="info"
|
icon="info"
|
||||||
@click="
|
@click="
|
||||||
openURL(
|
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>
|
<div class="text-subtitle2">SMTP Settings</div>
|
||||||
<q-separator />
|
<q-separator />
|
||||||
<q-card-section class="row">
|
<q-card-section class="row">
|
||||||
<div class="col-2">From:</div>
|
<div class="col-2">From email:</div>
|
||||||
<div class="col-4"></div>
|
<div class="col-4"></div>
|
||||||
<q-input
|
<q-input
|
||||||
outlined
|
outlined
|
||||||
@@ -226,6 +226,16 @@
|
|||||||
:rules="[(val) => isValidEmail(val) || 'Invalid email']"
|
:rules="[(val) => isValidEmail(val) || 'Invalid email']"
|
||||||
/>
|
/>
|
||||||
</q-card-section>
|
</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">
|
<q-card-section class="row">
|
||||||
<div class="col-2">Host:</div>
|
<div class="col-2">Host:</div>
|
||||||
<div class="col-4"></div>
|
<div class="col-4"></div>
|
||||||
@@ -379,7 +389,7 @@
|
|||||||
<q-tab-panel name="meshcentral">
|
<q-tab-panel name="meshcentral">
|
||||||
<div class="text-subtitle2">MeshCentral Settings</div>
|
<div class="text-subtitle2">MeshCentral Settings</div>
|
||||||
<q-separator />
|
<q-separator />
|
||||||
<q-card-section class="row">
|
<q-card-section class="row" v-if="!hosted">
|
||||||
<div class="col-4">Username:</div>
|
<div class="col-4">Username:</div>
|
||||||
<div class="col-2"></div>
|
<div class="col-2"></div>
|
||||||
<q-input
|
<q-input
|
||||||
@@ -395,7 +405,7 @@
|
|||||||
]"
|
]"
|
||||||
/>
|
/>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-card-section class="row">
|
<q-card-section class="row" v-if="!hosted">
|
||||||
<div class="col-4">Mesh Site:</div>
|
<div class="col-4">Mesh Site:</div>
|
||||||
<div class="col-2"></div>
|
<div class="col-2"></div>
|
||||||
<q-input
|
<q-input
|
||||||
@@ -405,7 +415,7 @@
|
|||||||
class="col-6"
|
class="col-6"
|
||||||
/>
|
/>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-card-section class="row">
|
<q-card-section class="row" v-if="!hosted">
|
||||||
<div class="col-4">Mesh Token:</div>
|
<div class="col-4">Mesh Token:</div>
|
||||||
<div class="col-2"></div>
|
<div class="col-2"></div>
|
||||||
<q-input
|
<q-input
|
||||||
@@ -415,7 +425,7 @@
|
|||||||
class="col-6"
|
class="col-6"
|
||||||
/>
|
/>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-card-section class="row">
|
<q-card-section class="row" v-if="!hosted">
|
||||||
<div class="col-4">Mesh Device Group Name:</div>
|
<div class="col-4">Mesh Device Group Name:</div>
|
||||||
<div class="col-2"></div>
|
<div class="col-2"></div>
|
||||||
<q-input
|
<q-input
|
||||||
@@ -425,17 +435,58 @@
|
|||||||
class="col-6"
|
class="col-6"
|
||||||
/>
|
/>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-card-section class="row">
|
<q-card-section class="row" v-if="!hosted">
|
||||||
<div class="col-4">
|
<div class="col-4 flex items-center">
|
||||||
Disable Auto Login for Remote Control and Remote background:
|
Sync Mesh Perms with TRMM:
|
||||||
|
<q-icon
|
||||||
|
right
|
||||||
|
name="ion-information-circle-outline"
|
||||||
|
size="sm"
|
||||||
|
class="cursor-pointer"
|
||||||
|
>
|
||||||
|
<q-tooltip class="text-caption">
|
||||||
|
It is recommended to keep this option enabled;
|
||||||
|
otherwise, all TRMM users will have full permissions in
|
||||||
|
MeshCentral regardless of their permissions in TRMM.
|
||||||
|
</q-tooltip>
|
||||||
|
</q-icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-2"></div>
|
<div class="col-2"></div>
|
||||||
<q-checkbox
|
<q-checkbox
|
||||||
dense
|
dense
|
||||||
v-model="settings.mesh_disable_auto_login"
|
:model-value="settings.sync_mesh_with_trmm"
|
||||||
|
@update:model-value="confirmSyncChange"
|
||||||
class="col-6"
|
class="col-6"
|
||||||
/>
|
/>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-card-section class="row items-center">
|
||||||
|
<div class="col-4 flex items-center">
|
||||||
|
Company Name:
|
||||||
|
<q-icon
|
||||||
|
name="ion-information-circle-outline"
|
||||||
|
size="sm"
|
||||||
|
class="q-ml-sm cursor-pointer"
|
||||||
|
>
|
||||||
|
<q-tooltip class="text-caption">
|
||||||
|
Adding your company name here will append it to the
|
||||||
|
user's full name that appears when doing a remote
|
||||||
|
control session, for example: 'John Doe - Amidaware
|
||||||
|
Inc.'
|
||||||
|
</q-tooltip>
|
||||||
|
</q-icon>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-2"></div>
|
||||||
|
|
||||||
|
<q-input
|
||||||
|
dense
|
||||||
|
outlined
|
||||||
|
v-model="settings.mesh_company_name"
|
||||||
|
class="col-6"
|
||||||
|
>
|
||||||
|
</q-input>
|
||||||
|
</q-card-section>
|
||||||
</q-tab-panel>
|
</q-tab-panel>
|
||||||
<q-tab-panel name="customfields">
|
<q-tab-panel name="customfields">
|
||||||
<CustomFields />
|
<CustomFields />
|
||||||
@@ -635,6 +686,11 @@ export default {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
hosted() {
|
||||||
|
return this.$store.state.hosted;
|
||||||
|
},
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
openURL(url) {
|
openURL(url) {
|
||||||
openURL(url);
|
openURL(url);
|
||||||
@@ -669,6 +725,19 @@ export default {
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
confirmSyncChange(newValue) {
|
||||||
|
this.$q
|
||||||
|
.dialog({
|
||||||
|
title: "Are you sure?",
|
||||||
|
message:
|
||||||
|
"This operation may take several minutes to complete in the background and can be very CPU/disk intensive, depending on your hardware and number of agents. Please allow time for the sync to fully complete.",
|
||||||
|
ok: { label: "Yes", color: "primary" },
|
||||||
|
cancel: { label: "No", color: "negative" },
|
||||||
|
})
|
||||||
|
.onOk(() => {
|
||||||
|
this.settings.sync_mesh_with_trmm = newValue;
|
||||||
|
});
|
||||||
|
},
|
||||||
showResetPatchPolicy() {
|
showResetPatchPolicy() {
|
||||||
this.$q.dialog({
|
this.$q.dialog({
|
||||||
component: ResetPatchPolicy,
|
component: ResetPatchPolicy,
|
||||||
@@ -711,13 +780,13 @@ export default {
|
|||||||
},
|
},
|
||||||
removeEmail(email) {
|
removeEmail(email) {
|
||||||
const removed = this.settings.email_alert_recipients.filter(
|
const removed = this.settings.email_alert_recipients.filter(
|
||||||
(k) => k !== email
|
(k) => k !== email,
|
||||||
);
|
);
|
||||||
this.settings.email_alert_recipients = removed;
|
this.settings.email_alert_recipients = removed;
|
||||||
},
|
},
|
||||||
removeSMSNumber(num) {
|
removeSMSNumber(num) {
|
||||||
const removed = this.settings.sms_alert_recipients.filter(
|
const removed = this.settings.sms_alert_recipients.filter(
|
||||||
(k) => k !== num
|
(k) => k !== num,
|
||||||
);
|
);
|
||||||
this.settings.sms_alert_recipients = removed;
|
this.settings.sms_alert_recipients = removed;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-dialog ref="dialog" @hide="onHide">
|
<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">
|
<q-splitter v-model="splitterModel">
|
||||||
<template v-slot:before>
|
<template v-slot:before>
|
||||||
<q-tabs dense v-model="tab" vertical class="text-primary">
|
<q-tabs dense v-model="tab" vertical class="text-primary">
|
||||||
@@ -201,7 +201,7 @@
|
|||||||
icon="info"
|
icon="info"
|
||||||
@click="
|
@click="
|
||||||
openURL(
|
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) => {
|
this.$axios.get("/core/urlaction/").then((r) => {
|
||||||
if (r.data.length === 0) {
|
if (r.data.length === 0) {
|
||||||
this.notifyWarning(
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,11 @@
|
|||||||
<q-dialog
|
<q-dialog
|
||||||
ref="dialogRef"
|
ref="dialogRef"
|
||||||
maximized
|
maximized
|
||||||
|
no-esc-dismiss
|
||||||
@hide="onDialogHide"
|
@hide="onDialogHide"
|
||||||
@show="loadEditor"
|
@show="loadEditor"
|
||||||
@before-hide="unloadEditor"
|
@before-hide="unloadEditor"
|
||||||
|
@keydown.esc.stop="closeEditor"
|
||||||
>
|
>
|
||||||
<q-card class="q-dialog-plugin">
|
<q-card class="q-dialog-plugin">
|
||||||
<q-bar>
|
<q-bar>
|
||||||
@@ -20,7 +22,7 @@
|
|||||||
@click="generateScriptOpenAI"
|
@click="generateScriptOpenAI"
|
||||||
/>
|
/>
|
||||||
<q-space />
|
<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-tooltip class="bg-white text-primary">Close</q-tooltip>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
</q-bar>
|
</q-bar>
|
||||||
@@ -190,7 +192,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</tactical-dropdown>
|
</tactical-dropdown>
|
||||||
<q-space />
|
<q-space />
|
||||||
<q-btn dense flat label="Cancel" v-close-popup />
|
<q-btn dense flat label="Cancel" @click="closeEditor" />
|
||||||
<q-btn
|
<q-btn
|
||||||
v-if="!readonly"
|
v-if="!readonly"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
@@ -220,6 +222,35 @@ import TestScriptModal from "@/components/scripts/TestScriptModal.vue";
|
|||||||
import TacticalDropdown from "@/components/ui/TacticalDropdown.vue";
|
import TacticalDropdown from "@/components/ui/TacticalDropdown.vue";
|
||||||
import * as monaco from "monaco-editor";
|
import * as monaco from "monaco-editor";
|
||||||
|
|
||||||
|
import jsonWorker from "monaco-editor/esm/vs/language/json/json.worker?worker";
|
||||||
|
import cssWorker from "monaco-editor/esm/vs/language/css/css.worker?worker";
|
||||||
|
import htmlWorker from "monaco-editor/esm/vs/language/html/html.worker?worker";
|
||||||
|
import jsWorker from "monaco-editor/esm/vs/language/typescript/ts.worker?worker";
|
||||||
|
import editorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker";
|
||||||
|
|
||||||
|
// https://github.com/microsoft/monaco-editor/issues/4045#issuecomment-1723787448
|
||||||
|
self.MonacoEnvironment = {
|
||||||
|
getWorker: function (workerId, label) {
|
||||||
|
switch (label) {
|
||||||
|
case "json":
|
||||||
|
return new jsonWorker();
|
||||||
|
case "css":
|
||||||
|
case "scss":
|
||||||
|
case "less":
|
||||||
|
return new cssWorker();
|
||||||
|
case "html":
|
||||||
|
case "handlebars":
|
||||||
|
case "razor":
|
||||||
|
return new htmlWorker();
|
||||||
|
case "typescript":
|
||||||
|
case "javascript":
|
||||||
|
return new jsWorker();
|
||||||
|
default:
|
||||||
|
return new editorWorker();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
// types
|
// types
|
||||||
import type { Script } from "@/types/scripts";
|
import type { Script } from "@/types/scripts";
|
||||||
|
|
||||||
@@ -294,11 +325,21 @@ const title = computed(() => {
|
|||||||
|
|
||||||
// convert highlighter language to match what ace expects
|
// convert highlighter language to match what ace expects
|
||||||
const lang = computed(() => {
|
const lang = computed(() => {
|
||||||
if (script.shell === "cmd") return "bat";
|
switch (script.shell) {
|
||||||
else if (script.shell === "powershell") return "powershell";
|
case "cmd":
|
||||||
else if (script.shell === "python") return "python";
|
return "bat";
|
||||||
else if (script.shell === "shell") return "shell";
|
case "powershell":
|
||||||
else return "";
|
return "powershell";
|
||||||
|
case "python":
|
||||||
|
return "python";
|
||||||
|
case "shell":
|
||||||
|
case "nushell":
|
||||||
|
return "shell";
|
||||||
|
case "deno":
|
||||||
|
return "typescript";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
async function submit() {
|
async function submit() {
|
||||||
@@ -337,12 +378,7 @@ const scriptEditor = ref<HTMLElement | null>(null);
|
|||||||
let editor: monaco.editor.IStandaloneCodeEditor;
|
let editor: monaco.editor.IStandaloneCodeEditor;
|
||||||
|
|
||||||
function loadEditor() {
|
function loadEditor() {
|
||||||
var modelUri = monaco.Uri.parse("model://new"); // a made up unique URI for our model
|
var model = monaco.editor.createModel(script.script_body, lang.value);
|
||||||
var model = monaco.editor.createModel(
|
|
||||||
script.script_body,
|
|
||||||
lang.value,
|
|
||||||
modelUri,
|
|
||||||
);
|
|
||||||
|
|
||||||
const theme = $q.dark.isActive ? "vs-dark" : "vs-light";
|
const theme = $q.dark.isActive ? "vs-dark" : "vs-light";
|
||||||
|
|
||||||
@@ -363,7 +399,23 @@ function loadEditor() {
|
|||||||
downloadScript(script.id, { with_snippets: props.readonly }).then((r) => {
|
downloadScript(script.id, { with_snippets: props.readonly }).then((r) => {
|
||||||
script.script_body = r.code;
|
script.script_body = r.code;
|
||||||
editor.setValue(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 for changes in language
|
||||||
watch(lang, () => {
|
watch(lang, () => {
|
||||||
@@ -394,6 +446,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
|
// component life cycle hooks
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
agentLoading.value = true;
|
agentLoading.value = true;
|
||||||
|
|||||||
@@ -175,6 +175,28 @@
|
|||||||
>
|
>
|
||||||
<q-tooltip> Shell </q-tooltip>
|
<q-tooltip> Shell </q-tooltip>
|
||||||
</q-icon>
|
</q-icon>
|
||||||
|
<q-icon
|
||||||
|
v-else-if="props.node.shell === 'nushell'"
|
||||||
|
name="mdi-code-greater-than"
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
<q-tooltip> Nushell </q-tooltip>
|
||||||
|
</q-icon>
|
||||||
|
<q-icon
|
||||||
|
v-else-if="props.node.shell === 'deno'"
|
||||||
|
name="mdi-language-typescript"
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
<q-tooltip> Deno </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
|
<span
|
||||||
class="q-pl-xs text-weight-bold"
|
class="q-pl-xs text-weight-bold"
|
||||||
@@ -463,6 +485,22 @@
|
|||||||
>
|
>
|
||||||
<q-tooltip> Shell </q-tooltip>
|
<q-tooltip> Shell </q-tooltip>
|
||||||
</q-icon>
|
</q-icon>
|
||||||
|
<q-icon
|
||||||
|
v-else-if="props.row.shell === 'nushell'"
|
||||||
|
size="sm"
|
||||||
|
name="mdi-code-greater-than"
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
<q-tooltip> Nushell </q-tooltip>
|
||||||
|
</q-icon>
|
||||||
|
<q-icon
|
||||||
|
v-else-if="props.row.shell === 'deno'"
|
||||||
|
size="sm"
|
||||||
|
name="mdi-language-typescript"
|
||||||
|
color="primary"
|
||||||
|
>
|
||||||
|
<q-tooltip> Deno </q-tooltip>
|
||||||
|
</q-icon>
|
||||||
</q-td>
|
</q-td>
|
||||||
<!-- supported platforms -->
|
<!-- supported platforms -->
|
||||||
<q-td key="supported_platforms" :props="props">
|
<q-td key="supported_platforms" :props="props">
|
||||||
@@ -488,6 +526,12 @@
|
|||||||
:props="props"
|
:props="props"
|
||||||
:style="{ color: props.row.hidden ? 'grey' : '' }"
|
: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) }}
|
{{ truncateText(props.row.name, 50) }}
|
||||||
<q-tooltip
|
<q-tooltip
|
||||||
v-if="props.row.name.length >= 50"
|
v-if="props.row.name.length >= 50"
|
||||||
@@ -550,6 +594,8 @@ import ScriptFormModal from "@/components/scripts/ScriptFormModal.vue";
|
|||||||
import ScriptSnippets from "@/components/scripts/ScriptSnippets.vue";
|
import ScriptSnippets from "@/components/scripts/ScriptSnippets.vue";
|
||||||
import TacticalTable from "@/components/ui/TacticalTable.vue";
|
import TacticalTable from "@/components/ui/TacticalTable.vue";
|
||||||
|
|
||||||
|
import trmmLogo from "@/assets/trmm_256.png";
|
||||||
|
|
||||||
// static data
|
// static data
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
@@ -620,7 +666,7 @@ export default {
|
|||||||
// setup vuex store
|
// setup vuex store
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
const showCommunityScripts = computed(
|
const showCommunityScripts = computed(
|
||||||
() => store.state.showCommunityScripts
|
() => store.state.showCommunityScripts,
|
||||||
);
|
);
|
||||||
|
|
||||||
// setup quasar plugins
|
// setup quasar plugins
|
||||||
@@ -721,7 +767,7 @@ export default {
|
|||||||
return showCommunityScripts.value
|
return showCommunityScripts.value
|
||||||
? scripts.value.filter((i) => !i.hidden)
|
? scripts.value.filter((i) => !i.hidden)
|
||||||
: scripts.value.filter(
|
: scripts.value.filter(
|
||||||
(i) => i.script_type !== "builtin" && !i.hidden
|
(i) => i.script_type !== "builtin" && !i.hidden,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -884,6 +930,7 @@ export default {
|
|||||||
loading,
|
loading,
|
||||||
showCommunityScripts,
|
showCommunityScripts,
|
||||||
showHiddenScripts,
|
showHiddenScripts,
|
||||||
|
trmmLogo,
|
||||||
|
|
||||||
// computed
|
// computed
|
||||||
visibleScripts,
|
visibleScripts,
|
||||||
|
|||||||
@@ -86,6 +86,35 @@ import { notifySuccess } from "@/utils/notify";
|
|||||||
// ui imports
|
// ui imports
|
||||||
import * as monaco from "monaco-editor";
|
import * as monaco from "monaco-editor";
|
||||||
|
|
||||||
|
import jsonWorker from "monaco-editor/esm/vs/language/json/json.worker?worker";
|
||||||
|
import cssWorker from "monaco-editor/esm/vs/language/css/css.worker?worker";
|
||||||
|
import htmlWorker from "monaco-editor/esm/vs/language/html/html.worker?worker";
|
||||||
|
import jsWorker from "monaco-editor/esm/vs/language/typescript/ts.worker?worker";
|
||||||
|
import editorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker";
|
||||||
|
|
||||||
|
// https://github.com/microsoft/monaco-editor/issues/4045#issuecomment-1723787448
|
||||||
|
self.MonacoEnvironment = {
|
||||||
|
getWorker: function (workerId, label) {
|
||||||
|
switch (label) {
|
||||||
|
case "json":
|
||||||
|
return new jsonWorker();
|
||||||
|
case "css":
|
||||||
|
case "scss":
|
||||||
|
case "less":
|
||||||
|
return new cssWorker();
|
||||||
|
case "html":
|
||||||
|
case "handlebars":
|
||||||
|
case "razor":
|
||||||
|
return new htmlWorker();
|
||||||
|
case "typescript":
|
||||||
|
case "javascript":
|
||||||
|
return new jsWorker();
|
||||||
|
default:
|
||||||
|
return new editorWorker();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
// types
|
// types
|
||||||
import type { ScriptSnippet } from "@/types/scripts";
|
import type { ScriptSnippet } from "@/types/scripts";
|
||||||
|
|
||||||
@@ -124,11 +153,21 @@ const title = computed(() => {
|
|||||||
|
|
||||||
// convert highlighter language to match what ace expects
|
// convert highlighter language to match what ace expects
|
||||||
const lang = computed(() => {
|
const lang = computed(() => {
|
||||||
if (snippet.shell === "cmd") return "bat";
|
switch (snippet.shell) {
|
||||||
else if (snippet.shell === "powershell") return "powershell";
|
case "cmd":
|
||||||
else if (snippet.shell === "python") return "python";
|
return "bat";
|
||||||
else if (snippet.shell === "shell") return "shell";
|
case "powershell":
|
||||||
else return "";
|
return "powershell";
|
||||||
|
case "python":
|
||||||
|
return "python";
|
||||||
|
case "shell":
|
||||||
|
case "nushell":
|
||||||
|
return "shell";
|
||||||
|
case "deno":
|
||||||
|
return "typescript";
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
async function submit() {
|
async function submit() {
|
||||||
@@ -150,8 +189,7 @@ const snippetEditor = ref<HTMLElement | null>(null);
|
|||||||
let editor: monaco.editor.IStandaloneCodeEditor;
|
let editor: monaco.editor.IStandaloneCodeEditor;
|
||||||
|
|
||||||
function loadEditor() {
|
function loadEditor() {
|
||||||
var modelUri = monaco.Uri.parse("model://snippet"); // a made up unique URI for our model
|
var model = monaco.editor.createModel(snippet.code, lang.value);
|
||||||
var model = monaco.editor.createModel(snippet.code, lang.value, modelUri);
|
|
||||||
|
|
||||||
const theme = $q.dark.isActive ? "vs-dark" : "vs-light";
|
const theme = $q.dark.isActive ? "vs-dark" : "vs-light";
|
||||||
|
|
||||||
|
|||||||
@@ -124,6 +124,22 @@
|
|||||||
>
|
>
|
||||||
<q-tooltip> Shell </q-tooltip>
|
<q-tooltip> Shell </q-tooltip>
|
||||||
</q-icon>
|
</q-icon>
|
||||||
|
<q-icon
|
||||||
|
v-else-if="props.row.shell === 'nushell'"
|
||||||
|
name="mdi-nushell"
|
||||||
|
color="primary"
|
||||||
|
size="sm"
|
||||||
|
>
|
||||||
|
<q-tooltip> Nushell </q-tooltip>
|
||||||
|
</q-icon>
|
||||||
|
<q-icon
|
||||||
|
v-else-if="props.row.shell === 'deno'"
|
||||||
|
name="mdi-typescript"
|
||||||
|
color="primary"
|
||||||
|
size="sm"
|
||||||
|
>
|
||||||
|
<q-tooltip> Deno </q-tooltip>
|
||||||
|
</q-icon>
|
||||||
</q-td>
|
</q-td>
|
||||||
<!-- name -->
|
<!-- name -->
|
||||||
<q-td>{{ props.row.name }}</q-td>
|
<q-td>{{ props.row.name }}</q-td>
|
||||||
|
|||||||
@@ -8,8 +8,25 @@
|
|||||||
<q-tooltip class="bg-white text-primary">Close</q-tooltip>
|
<q-tooltip class="bg-white text-primary">Close</q-tooltip>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
</q-bar>
|
</q-bar>
|
||||||
<q-card-section class="scroll" style="max-height: 70vh; height: 70vh">
|
<q-card-section style="height: 70vh" class="scroll">
|
||||||
<pre v-if="ret">{{ ret }}</pre>
|
<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-inner-loading :showing="loading" />
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
</q-card>
|
</q-card>
|
||||||
@@ -34,7 +51,12 @@ export default {
|
|||||||
const { dialogRef, onDialogHide } = useDialogPluginComponent();
|
const { dialogRef, onDialogHide } = useDialogPluginComponent();
|
||||||
|
|
||||||
// main run script functionality
|
// main run script functionality
|
||||||
const ret = ref(null);
|
const ret = ref({
|
||||||
|
execution_time: "",
|
||||||
|
retcode: "",
|
||||||
|
stdout: "",
|
||||||
|
stderr: "",
|
||||||
|
});
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|
||||||
async function runTestScript() {
|
async function runTestScript() {
|
||||||
|
|||||||
@@ -87,6 +87,7 @@
|
|||||||
:done="step > 2"
|
:done="step > 2"
|
||||||
:error="!isValidStep2"
|
:error="!isValidStep2"
|
||||||
>
|
>
|
||||||
|
<div class="scroll" style="max-height: 60vh">
|
||||||
<q-form @submit.prevent="addAction">
|
<q-form @submit.prevent="addAction">
|
||||||
<div class="row q-pa-sm q-gutter-x-xs items-center">
|
<div class="row q-pa-sm q-gutter-x-xs items-center">
|
||||||
<div class="text-subtitle2 col-12">Action Type:</div>
|
<div class="text-subtitle2 col-12">Action Type:</div>
|
||||||
@@ -200,7 +201,7 @@
|
|||||||
<q-tooltip>Continue task if an action fails</q-tooltip>
|
<q-tooltip>Continue task if an action fails</q-tooltip>
|
||||||
</q-checkbox>
|
</q-checkbox>
|
||||||
</div>
|
</div>
|
||||||
<div class="scroll q-pt-sm" style="height: 40vh; max-height: 40vh">
|
<div class="q-pt-sm" style="height: 150px">
|
||||||
<draggable
|
<draggable
|
||||||
class="q-list"
|
class="q-list"
|
||||||
handle=".handle"
|
handle=".handle"
|
||||||
@@ -263,6 +264,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</draggable>
|
</draggable>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</q-step>
|
</q-step>
|
||||||
|
|
||||||
<q-step :name="3" title="Choose Schedule" :error="!isValidStep3">
|
<q-step :name="3" title="Choose Schedule" :error="!isValidStep3">
|
||||||
@@ -283,7 +285,7 @@
|
|||||||
<q-card-section
|
<q-card-section
|
||||||
v-if="
|
v-if="
|
||||||
['runonce', 'daily', 'weekly', 'monthly'].includes(
|
['runonce', 'daily', 'weekly', 'monthly'].includes(
|
||||||
state.task_type
|
state.task_type,
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
class="row"
|
class="row"
|
||||||
@@ -314,6 +316,22 @@
|
|||||||
/>
|
/>
|
||||||
</q-card-section>
|
</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 -->
|
<!-- daily options -->
|
||||||
<q-card-section v-if="state.task_type === 'daily'" class="row">
|
<q-card-section v-if="state.task_type === 'daily'" class="row">
|
||||||
<!-- daily interval -->
|
<!-- daily interval -->
|
||||||
@@ -579,7 +597,8 @@
|
|||||||
<q-card-section
|
<q-card-section
|
||||||
v-if="
|
v-if="
|
||||||
state.task_type !== 'checkfailure' &&
|
state.task_type !== 'checkfailure' &&
|
||||||
state.task_type !== 'manual'
|
state.task_type !== 'manual' &&
|
||||||
|
state.task_type !== 'onboarding'
|
||||||
"
|
"
|
||||||
class="row"
|
class="row"
|
||||||
>
|
>
|
||||||
@@ -617,7 +636,7 @@
|
|||||||
(val) =>
|
(val) =>
|
||||||
convertPeriodToSeconds(val) >=
|
convertPeriodToSeconds(val) >=
|
||||||
convertPeriodToSeconds(
|
convertPeriodToSeconds(
|
||||||
state.task_repetition_interval
|
state.task_repetition_interval,
|
||||||
) ||
|
) ||
|
||||||
'Repetition duration must be greater than repetition interval',
|
'Repetition duration must be greater than repetition interval',
|
||||||
]"
|
]"
|
||||||
@@ -712,7 +731,7 @@
|
|||||||
@click="
|
@click="
|
||||||
validateStep(
|
validateStep(
|
||||||
step === 1 ? $refs.taskGeneralForm : undefined,
|
step === 1 ? $refs.taskGeneralForm : undefined,
|
||||||
$refs.stepper
|
$refs.stepper,
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
color="primary"
|
color="primary"
|
||||||
@@ -769,6 +788,7 @@ const taskTypeOptions = [
|
|||||||
{ label: "Monthly", value: "monthly" },
|
{ label: "Monthly", value: "monthly" },
|
||||||
{ label: "Run Once", value: "runonce" },
|
{ label: "Run Once", value: "runonce" },
|
||||||
{ label: "On check failure", value: "checkfailure" },
|
{ label: "On check failure", value: "checkfailure" },
|
||||||
|
{ label: "Onboarding", value: "onboarding" },
|
||||||
{ label: "Manual", value: "manual" },
|
{ label: "Manual", value: "manual" },
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -933,7 +953,7 @@ export default {
|
|||||||
task.value.actions.push({
|
task.value.actions.push({
|
||||||
type: "script",
|
type: "script",
|
||||||
name: scriptOptions.value.find(
|
name: scriptOptions.value.find(
|
||||||
(option) => option.value === script.value
|
(option) => option.value === script.value,
|
||||||
).label,
|
).label,
|
||||||
script: script.value,
|
script: script.value,
|
||||||
timeout: defaultTimeout.value,
|
timeout: defaultTimeout.value,
|
||||||
@@ -1019,13 +1039,13 @@ export default {
|
|||||||
// remove milliseconds and Z to work with native date input
|
// remove milliseconds and Z to work with native date input
|
||||||
task.value.run_time_date = formatDateInputField(
|
task.value.run_time_date = formatDateInputField(
|
||||||
task.value.run_time_date,
|
task.value.run_time_date,
|
||||||
true
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (task.value.expire_date)
|
if (task.value.expire_date)
|
||||||
task.value.expire_date = formatDateInputField(
|
task.value.expire_date = formatDateInputField(
|
||||||
task.value.expire_date,
|
task.value.expire_date,
|
||||||
true
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
// set task type if monthlydow is being used
|
// set task type if monthlydow is being used
|
||||||
@@ -1069,7 +1089,7 @@ export default {
|
|||||||
task.value.monthly_weeks_of_month = [];
|
task.value.monthly_weeks_of_month = [];
|
||||||
task.value.task_instance_policy = 0;
|
task.value.task_instance_policy = 0;
|
||||||
task.value.expire_date = null;
|
task.value.expire_date = null;
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// check the collector box when editing task and custom field is set
|
// check the collector box when editing task and custom field is set
|
||||||
|
|||||||
@@ -25,13 +25,21 @@
|
|||||||
:key="mapOptions ? scope.opt.value : scope.opt"
|
:key="mapOptions ? scope.opt.value : scope.opt"
|
||||||
>
|
>
|
||||||
<q-item-section>
|
<q-item-section>
|
||||||
<q-item-label
|
<q-item-label v-html="mapOptions ? scope.opt.label : scope.opt" />
|
||||||
v-html="mapOptions ? scope.opt.label : scope.opt"
|
</q-item-section>
|
||||||
></q-item-label>
|
<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>
|
||||||
<q-item-section v-if="filtered && mapOptions && scope.opt.cat" side>{{
|
|
||||||
scope.opt.cat
|
|
||||||
}}</q-item-section>
|
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-item-label
|
<q-item-label
|
||||||
v-if="scope.opt.category"
|
v-if="scope.opt.category"
|
||||||
@@ -80,7 +88,7 @@ export default {
|
|||||||
|
|
||||||
if (!props.mapOptions)
|
if (!props.mapOptions)
|
||||||
filteredOptions.value = props.options.filter(
|
filteredOptions.value = props.options.filter(
|
||||||
(v) => v.toLowerCase().indexOf(needle) > -1
|
(v) => v.toLowerCase().indexOf(needle) > -1,
|
||||||
);
|
);
|
||||||
else
|
else
|
||||||
filteredOptions.value = props.options.filter((v) => {
|
filteredOptions.value = props.options.filter((v) => {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export function useScriptDropdown(setScript = null, { onMount = false } = {}) {
|
|||||||
// specify parameters to filter out community scripts
|
// specify parameters to filter out community scripts
|
||||||
async function getScriptOptions(showCommunityScripts = false) {
|
async function getScriptOptions(showCommunityScripts = false) {
|
||||||
scriptOptions.value = Object.freeze(
|
scriptOptions.value = Object.freeze(
|
||||||
formatScriptOptions(await fetchScripts({ showCommunityScripts }))
|
formatScriptOptions(await fetchScripts({ showCommunityScripts })),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ export function useScriptDropdown(setScript = null, { onMount = false } = {}) {
|
|||||||
watch([script, scriptOptions], () => {
|
watch([script, scriptOptions], () => {
|
||||||
if (script.value && scriptOptions.value.length > 0) {
|
if (script.value && scriptOptions.value.length > 0) {
|
||||||
const tmpScript = scriptOptions.value.find(
|
const tmpScript = scriptOptions.value.find(
|
||||||
(i) => i.value === script.value
|
(i) => i.value === script.value,
|
||||||
);
|
);
|
||||||
defaultTimeout.value = tmpScript.timeout;
|
defaultTimeout.value = tmpScript.timeout;
|
||||||
defaultArgs.value = tmpScript.args;
|
defaultArgs.value = tmpScript.args;
|
||||||
@@ -65,4 +65,6 @@ export const shellOptions = [
|
|||||||
{ label: "Batch", value: "cmd" },
|
{ label: "Batch", value: "cmd" },
|
||||||
{ label: "Python", value: "python" },
|
{ label: "Python", value: "python" },
|
||||||
{ label: "Shell", value: "shell" },
|
{ label: "Shell", value: "shell" },
|
||||||
|
{ label: "Nushell", value: "nushell" },
|
||||||
|
{ label: "Deno", value: "deno" },
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ For details, see: https://license.tacticalrmm.com/ee
|
|||||||
:rows="reportTemplates"
|
:rows="reportTemplates"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:loading="isLoading"
|
:loading="isLoading"
|
||||||
:pagination="{ rowsPerPage: 0, sortBy: 'name', descending: true }"
|
:pagination="{ rowsPerPage: 0, sortBy: 'name', descending: false }"
|
||||||
:filter="search"
|
:filter="search"
|
||||||
row-key="id"
|
row-key="id"
|
||||||
binary-state-sort
|
binary-state-sort
|
||||||
|
|||||||
@@ -25,8 +25,8 @@
|
|||||||
If you have downgraded or cancelled your sponsorship, please delete
|
If you have downgraded or cancelled your sponsorship, please delete
|
||||||
your token from the Code Signing modal and refresh to get rid of this
|
your token from the Code Signing modal and refresh to get rid of this
|
||||||
banner.<br /><br />
|
banner.<br /><br />
|
||||||
For any issues or to renew your sponsorship please email
|
For any issues or to renew your sponsorship please open a ticket at
|
||||||
support@amidaware.com<br /><br
|
support.amidaware.com<br /><br
|
||||||
/></span>
|
/></span>
|
||||||
<q-btn
|
<q-btn
|
||||||
color="dark"
|
color="dark"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { AgentPlatformType } from "@/types/agents";
|
import type { AgentPlatformType } from "@/types/agents";
|
||||||
|
|
||||||
export type ScriptShellType = "powershell" | "cmd" | "shell" | "python";
|
export type ScriptShellType = "powershell" | "cmd" | "shell" | "python" | "nushell" | "deno";
|
||||||
|
|
||||||
export interface Script {
|
export interface Script {
|
||||||
id?: number;
|
id?: number;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { date } from "quasar";
|
import { date } from "quasar";
|
||||||
import { validateTimePeriod } from "@/utils/validation";
|
import { validateTimePeriod } from "@/utils/validation";
|
||||||
|
import trmmLogo from "@/assets/trmm_256.png";
|
||||||
// dropdown options formatting
|
// dropdown options formatting
|
||||||
|
|
||||||
export function removeExtraOptionCategories(array) {
|
export function removeExtraOptionCategories(array) {
|
||||||
@@ -24,7 +25,7 @@ function _formatOptions(
|
|||||||
flat = false,
|
flat = false,
|
||||||
allowDuplicates = true,
|
allowDuplicates = true,
|
||||||
appendToOptionObject = {},
|
appendToOptionObject = {},
|
||||||
}
|
},
|
||||||
) {
|
) {
|
||||||
if (!flat)
|
if (!flat)
|
||||||
// returns array of options in object format [{label: label, value: 1}]
|
// returns array of options in object format [{label: label, value: 1}]
|
||||||
@@ -64,6 +65,7 @@ export function formatScriptOptions(data) {
|
|||||||
data.forEach((script) => {
|
data.forEach((script) => {
|
||||||
if (script.category === cat) {
|
if (script.category === cat) {
|
||||||
tmp.push({
|
tmp.push({
|
||||||
|
img_right: script.script_type === "builtin" ? trmmLogo : undefined,
|
||||||
label: script.name,
|
label: script.name,
|
||||||
value: script.id,
|
value: script.id,
|
||||||
timeout: script.default_timeout,
|
timeout: script.default_timeout,
|
||||||
@@ -100,7 +102,7 @@ export function formatScriptOptions(data) {
|
|||||||
export function formatAgentOptions(
|
export function formatAgentOptions(
|
||||||
data,
|
data,
|
||||||
flat = false,
|
flat = false,
|
||||||
value_field = "agent_id"
|
value_field = "agent_id",
|
||||||
) {
|
) {
|
||||||
if (flat) {
|
if (flat) {
|
||||||
// returns just agent hostnames in array
|
// returns just agent hostnames in array
|
||||||
@@ -185,7 +187,7 @@ export function formatSiteOptions(data, flat = false) {
|
|||||||
label: "name",
|
label: "name",
|
||||||
flat: flat,
|
flat: flat,
|
||||||
appendToOptionObject: { cat: client.name },
|
appendToOptionObject: { cat: client.name },
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -361,7 +363,7 @@ export function convertToBitArray(number) {
|
|||||||
bitArray.push(1);
|
bitArray.push(1);
|
||||||
} else {
|
} else {
|
||||||
bitArray.push(
|
bitArray.push(
|
||||||
parseInt(binary.slice(i), 2) - parseInt(binary.slice(i + 1), 2)
|
parseInt(binary.slice(i), 2) - parseInt(binary.slice(i + 1), 2),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,26 @@
|
|||||||
:options="allTimezones"
|
:options="allTimezones"
|
||||||
/>
|
/>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-card-section>
|
||||||
|
<div>
|
||||||
|
Company name:
|
||||||
|
<q-icon
|
||||||
|
name="ion-information-circle-outline"
|
||||||
|
size="sm"
|
||||||
|
class="q-ml-sm cursor-pointer"
|
||||||
|
>
|
||||||
|
<q-tooltip class="text-caption">
|
||||||
|
Adding your company name here will append it to the user's
|
||||||
|
full name that appears when doing a remote control session,
|
||||||
|
for example: 'John Doe - Amidaware Inc.'
|
||||||
|
</q-tooltip>
|
||||||
|
</q-icon>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<q-input dense outlined v-model="companyname"> </q-input>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
<q-card-actions align="center">
|
<q-card-actions align="center">
|
||||||
<q-btn
|
<q-btn
|
||||||
label="Finish"
|
label="Finish"
|
||||||
@@ -86,6 +106,7 @@ export default {
|
|||||||
allTimezones: [],
|
allTimezones: [],
|
||||||
timezone: null,
|
timezone: null,
|
||||||
arch: "64",
|
arch: "64",
|
||||||
|
companyname: "",
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -95,6 +116,7 @@ export default {
|
|||||||
client: this.client,
|
client: this.client,
|
||||||
site: this.site,
|
site: this.site,
|
||||||
timezone: this.timezone,
|
timezone: this.timezone,
|
||||||
|
companyname: this.companyname,
|
||||||
initialsetup: true,
|
initialsetup: true,
|
||||||
};
|
};
|
||||||
this.$axios
|
this.$axios
|
||||||
|
|||||||
@@ -63,6 +63,7 @@
|
|||||||
autofocus
|
autofocus
|
||||||
outlined
|
outlined
|
||||||
v-model="credentials.twofactor"
|
v-model="credentials.twofactor"
|
||||||
|
autocomplete="one-time-code"
|
||||||
:rules="[
|
:rules="[
|
||||||
(val) =>
|
(val) =>
|
||||||
(val && val.length > 0) || 'This field is required',
|
(val && val.length > 0) || 'This field is required',
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ export default {
|
|||||||
control.value = data.control;
|
control.value = data.control;
|
||||||
status.value = data.status;
|
status.value = data.status;
|
||||||
useMeta({
|
useMeta({
|
||||||
title: `${data.hostname} - ${data.client} - ${data.site} | Remote Background`,
|
title: `${data.hostname} - ${data.client} - ${data.site} | Take Control`,
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
|||||||
Reference in New Issue
Block a user