Compare commits
	
		
			33 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 | ||
| 
						 | 
					fe8d88497f | 
							
								
								
									
										8
									
								
								.github/workflows/build-release.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.github/workflows/build-release.yml
									
									
									
									
										vendored
									
									
								
							@@ -11,11 +11,11 @@ jobs:
 | 
			
		||||
    name: Build web
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
      - uses: actions/checkout@v3
 | 
			
		||||
      - uses: actions/checkout@v4
 | 
			
		||||
 | 
			
		||||
      - uses: actions/setup-node@v3
 | 
			
		||||
      - uses: actions/setup-node@v4
 | 
			
		||||
        with:
 | 
			
		||||
          node-version: 18
 | 
			
		||||
          node-version: "20.11.1"
 | 
			
		||||
 | 
			
		||||
      - run: touch env-config.js
 | 
			
		||||
 | 
			
		||||
@@ -29,6 +29,6 @@ jobs:
 | 
			
		||||
        run: tar -czvf trmm-web-${{github.ref_name}}.tar.gz dist/
 | 
			
		||||
 | 
			
		||||
      - name: Release
 | 
			
		||||
        uses: softprops/action-gh-release@v1
 | 
			
		||||
        uses: softprops/action-gh-release@v2
 | 
			
		||||
        with:
 | 
			
		||||
          files: trmm-web-${{github.ref_name}}.tar.gz
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										720
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										720
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										47
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								package.json
									
									
									
									
									
								
							@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "web",
 | 
			
		||||
  "version": "0.101.40",
 | 
			
		||||
  "version": "0.101.43",
 | 
			
		||||
  "private": true,
 | 
			
		||||
  "productName": "Tactical RMM",
 | 
			
		||||
  "scripts": {
 | 
			
		||||
@@ -11,33 +11,36 @@
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@quasar/extras": "1.16.9",
 | 
			
		||||
    "apexcharts": "3.45.2",
 | 
			
		||||
    "axios": "1.6.7",
 | 
			
		||||
    "dotenv": "16.4.1",
 | 
			
		||||
    "apexcharts": "3.48.0",
 | 
			
		||||
    "axios": "1.6.8",
 | 
			
		||||
    "dotenv": "16.4.5",
 | 
			
		||||
    "pinia": "^2.1.7",
 | 
			
		||||
    "qrcode.vue": "3.4.1",
 | 
			
		||||
    "quasar": "2.14.3",
 | 
			
		||||
    "vue": "3.4.15",
 | 
			
		||||
    "vue3-apexcharts": "1.4.4",
 | 
			
		||||
    "quasar": "2.15.1",
 | 
			
		||||
    "vue": "3.4.21",
 | 
			
		||||
    "vue3-apexcharts": "1.5.2",
 | 
			
		||||
    "vuedraggable": "4.1.0",
 | 
			
		||||
    "vue-router": "4.2.5",
 | 
			
		||||
    "@vueuse/core": "10.7.2",
 | 
			
		||||
    "@vueuse/shared": "10.7.2",
 | 
			
		||||
    "monaco-editor": "0.45.0",
 | 
			
		||||
    "vue-router": "4.3.0",
 | 
			
		||||
    "@vueuse/core": "10.9.0",
 | 
			
		||||
    "@vueuse/shared": "10.9.0",
 | 
			
		||||
    "monaco-editor": "0.47.0",
 | 
			
		||||
    "vuex": "4.1.0",
 | 
			
		||||
    "yaml": "2.3.4"
 | 
			
		||||
    "xterm": "^5.3.0",
 | 
			
		||||
    "xterm-addon-fit": "^0.8.0",
 | 
			
		||||
    "yaml": "2.4.1"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@quasar/cli": "2.3.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",
 | 
			
		||||
    "@quasar/cli": "2.4.0",
 | 
			
		||||
    "@intlify/unplugin-vue-i18n": "3.0.1",
 | 
			
		||||
    "@quasar/app-vite": "1.8.0",
 | 
			
		||||
    "@types/node": "20.11.30",
 | 
			
		||||
    "@typescript-eslint/eslint-plugin": "7.3.1",
 | 
			
		||||
    "@typescript-eslint/parser": "7.3.1",
 | 
			
		||||
    "autoprefixer": "10.4.18",
 | 
			
		||||
    "eslint": "8.57.0",
 | 
			
		||||
    "eslint-config-prettier": "9.1.0",
 | 
			
		||||
    "eslint-plugin-vue": "8.7.1",
 | 
			
		||||
    "prettier": "3.2.4",
 | 
			
		||||
    "typescript": "5.3.3"
 | 
			
		||||
    "prettier": "3.2.5",
 | 
			
		||||
    "typescript": "5.4.3"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -36,7 +36,7 @@ module.exports = configure(function (/* ctx */) {
 | 
			
		||||
 | 
			
		||||
    // https://github.com/quasarframework/quasar/tree/dev/extras
 | 
			
		||||
    extras: [
 | 
			
		||||
      // 'ionicons-v4',
 | 
			
		||||
      "ionicons-v4",
 | 
			
		||||
      "mdi-v5",
 | 
			
		||||
      "fontawesome-v6",
 | 
			
		||||
      // '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
 | 
			
		||||
    build: {
 | 
			
		||||
      target: {
 | 
			
		||||
        browser: ["es2021"],
 | 
			
		||||
        node: "node16",
 | 
			
		||||
        browser: ["es2022"],
 | 
			
		||||
        node: "node20",
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
      vueRouterMode: "history", // available values: 'hash', 'history'
 | 
			
		||||
 
 | 
			
		||||
@@ -191,6 +191,11 @@ export async function agentRebootNow(agent_id) {
 | 
			
		||||
  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 = {}) {
 | 
			
		||||
  const { data } = await axios.post(
 | 
			
		||||
    `${baseUrl}/${agent_id}/meshcentral/recover/`,
 | 
			
		||||
 
 | 
			
		||||
@@ -170,7 +170,7 @@
 | 
			
		||||
                overdueAlert(
 | 
			
		||||
                  'dashboard',
 | 
			
		||||
                  props.row,
 | 
			
		||||
                  props.row.overdue_dashboard_alert
 | 
			
		||||
                  props.row.overdue_dashboard_alert,
 | 
			
		||||
                )
 | 
			
		||||
              "
 | 
			
		||||
              v-model="props.row.overdue_dashboard_alert"
 | 
			
		||||
@@ -431,8 +431,8 @@ export default {
 | 
			
		||||
            return false;
 | 
			
		||||
          else if (availability === "expired") {
 | 
			
		||||
            let now = new Date();
 | 
			
		||||
            let lastSeen = date.extractDate(row.last_seen, "MM DD YYYY HH:mm");
 | 
			
		||||
            let diff = date.getDateDiff(now, lastSeen, "days");
 | 
			
		||||
            let last_seen_unix = new Date(row.boot_time * 1000);
 | 
			
		||||
            let diff = date.getDateDiff(now, last_seen_unix, "days");
 | 
			
		||||
            if (diff < 30) return false;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -107,7 +107,7 @@
 | 
			
		||||
              />
 | 
			
		||||
              <q-checkbox
 | 
			
		||||
                v-model="localRole.can_reboot_agents"
 | 
			
		||||
                label="Reboot Agents"
 | 
			
		||||
                label="Shutdown / Reboot Agents"
 | 
			
		||||
              />
 | 
			
		||||
              <q-checkbox
 | 
			
		||||
                v-model="localRole.can_send_wol"
 | 
			
		||||
 
 | 
			
		||||
@@ -176,6 +176,13 @@
 | 
			
		||||
      </q-menu>
 | 
			
		||||
    </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-section side>
 | 
			
		||||
        <q-icon size="xs" name="policy" />
 | 
			
		||||
@@ -192,9 +199,9 @@
 | 
			
		||||
      "
 | 
			
		||||
    >
 | 
			
		||||
      <q-item-section side>
 | 
			
		||||
        <q-icon size="xs" name="integration_instructions" />
 | 
			
		||||
        <q-icon size="xs" name="analytics" />
 | 
			
		||||
      </q-item-section>
 | 
			
		||||
      <q-item-section>Integrations</q-item-section>
 | 
			
		||||
      <q-item-section>Reporting</q-item-section>
 | 
			
		||||
      <q-item-section side>
 | 
			
		||||
        <q-icon name="keyboard_arrow_right" />
 | 
			
		||||
      </q-item-section>
 | 
			
		||||
@@ -231,6 +238,7 @@ import { fetchURLActions, runURLAction } from "@/api/core";
 | 
			
		||||
import {
 | 
			
		||||
  editAgent,
 | 
			
		||||
  agentRebootNow,
 | 
			
		||||
  agentShutdown,
 | 
			
		||||
  sendAgentPing,
 | 
			
		||||
  removeAgent,
 | 
			
		||||
  runRemoteBackground,
 | 
			
		||||
@@ -298,7 +306,7 @@ export default {
 | 
			
		||||
 | 
			
		||||
        if (urlActions.value.length === 0) {
 | 
			
		||||
          notifyWarning(
 | 
			
		||||
            "No URL Actions configured. Go to Settings > Global Settings > URL Actions"
 | 
			
		||||
            "No URL Actions configured. Go to Settings > Global Settings > URL Actions",
 | 
			
		||||
          );
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
@@ -364,7 +372,7 @@ export default {
 | 
			
		||||
        notifySuccess(
 | 
			
		||||
          `Maintenance mode was ${
 | 
			
		||||
            agent.maintenance_mode ? "disabled" : "enabled"
 | 
			
		||||
          } on ${agent.hostname}`
 | 
			
		||||
          } on ${agent.hostname}`,
 | 
			
		||||
        );
 | 
			
		||||
        store.commit("setRefreshSummaryTab", true);
 | 
			
		||||
        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) {
 | 
			
		||||
      $q.dialog({
 | 
			
		||||
        component: PolicyAdd,
 | 
			
		||||
@@ -505,7 +539,7 @@ export default {
 | 
			
		||||
          notifySuccess(data);
 | 
			
		||||
          refreshDashboard(
 | 
			
		||||
            false /* clearTreeSelected */,
 | 
			
		||||
            true /* clearSubTable */
 | 
			
		||||
            true /* clearSubTable */,
 | 
			
		||||
          );
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
          console.error(e);
 | 
			
		||||
@@ -534,6 +568,7 @@ export default {
 | 
			
		||||
      runChecks,
 | 
			
		||||
      showRebootLaterModal,
 | 
			
		||||
      rebootNow,
 | 
			
		||||
      shutdown,
 | 
			
		||||
      showPolicyAdd,
 | 
			
		||||
      showAgentRecovery,
 | 
			
		||||
      pingAgent,
 | 
			
		||||
 
 | 
			
		||||
@@ -389,7 +389,7 @@
 | 
			
		||||
              <q-tab-panel name="meshcentral">
 | 
			
		||||
                <div class="text-subtitle2">MeshCentral Settings</div>
 | 
			
		||||
                <q-separator />
 | 
			
		||||
                <q-card-section class="row">
 | 
			
		||||
                <q-card-section class="row" v-if="!hosted">
 | 
			
		||||
                  <div class="col-4">Username:</div>
 | 
			
		||||
                  <div class="col-2"></div>
 | 
			
		||||
                  <q-input
 | 
			
		||||
@@ -405,7 +405,7 @@
 | 
			
		||||
                    ]"
 | 
			
		||||
                  />
 | 
			
		||||
                </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-2"></div>
 | 
			
		||||
                  <q-input
 | 
			
		||||
@@ -415,7 +415,7 @@
 | 
			
		||||
                    class="col-6"
 | 
			
		||||
                  />
 | 
			
		||||
                </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-2"></div>
 | 
			
		||||
                  <q-input
 | 
			
		||||
@@ -425,7 +425,7 @@
 | 
			
		||||
                    class="col-6"
 | 
			
		||||
                  />
 | 
			
		||||
                </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-2"></div>
 | 
			
		||||
                  <q-input
 | 
			
		||||
@@ -435,17 +435,58 @@
 | 
			
		||||
                    class="col-6"
 | 
			
		||||
                  />
 | 
			
		||||
                </q-card-section>
 | 
			
		||||
                <q-card-section class="row">
 | 
			
		||||
                  <div class="col-4">
 | 
			
		||||
                    Disable Auto Login for Remote Control and Remote background:
 | 
			
		||||
                <q-card-section class="row" v-if="!hosted">
 | 
			
		||||
                  <div class="col-4 flex items-center">
 | 
			
		||||
                    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 class="col-2"></div>
 | 
			
		||||
                  <q-checkbox
 | 
			
		||||
                    dense
 | 
			
		||||
                    v-model="settings.mesh_disable_auto_login"
 | 
			
		||||
                    :model-value="settings.sync_mesh_with_trmm"
 | 
			
		||||
                    @update:model-value="confirmSyncChange"
 | 
			
		||||
                    class="col-6"
 | 
			
		||||
                  />
 | 
			
		||||
                </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 name="customfields">
 | 
			
		||||
                <CustomFields />
 | 
			
		||||
@@ -645,6 +686,11 @@ export default {
 | 
			
		||||
      ],
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    hosted() {
 | 
			
		||||
      return this.$store.state.hosted;
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    openURL(url) {
 | 
			
		||||
      openURL(url);
 | 
			
		||||
@@ -679,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() {
 | 
			
		||||
      this.$q.dialog({
 | 
			
		||||
        component: ResetPatchPolicy,
 | 
			
		||||
 
 | 
			
		||||
@@ -222,6 +222,35 @@ import TestScriptModal from "@/components/scripts/TestScriptModal.vue";
 | 
			
		||||
import TacticalDropdown from "@/components/ui/TacticalDropdown.vue";
 | 
			
		||||
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
 | 
			
		||||
import type { Script } from "@/types/scripts";
 | 
			
		||||
 | 
			
		||||
@@ -296,11 +325,21 @@ const title = computed(() => {
 | 
			
		||||
 | 
			
		||||
// convert highlighter language to match what ace expects
 | 
			
		||||
const lang = computed(() => {
 | 
			
		||||
  if (script.shell === "cmd") return "bat";
 | 
			
		||||
  else if (script.shell === "powershell") return "powershell";
 | 
			
		||||
  else if (script.shell === "python") return "python";
 | 
			
		||||
  else if (script.shell === "shell") return "shell";
 | 
			
		||||
  else return "";
 | 
			
		||||
  switch (script.shell) {
 | 
			
		||||
    case "cmd":
 | 
			
		||||
      return "bat";
 | 
			
		||||
    case "powershell":
 | 
			
		||||
      return "powershell";
 | 
			
		||||
    case "python":
 | 
			
		||||
      return "python";
 | 
			
		||||
    case "shell":
 | 
			
		||||
    case "nushell":
 | 
			
		||||
      return "shell";
 | 
			
		||||
    case "deno":
 | 
			
		||||
      return "typescript";
 | 
			
		||||
    default:
 | 
			
		||||
      return "";
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
async function submit() {
 | 
			
		||||
@@ -339,12 +378,7 @@ const scriptEditor = ref<HTMLElement | null>(null);
 | 
			
		||||
let editor: monaco.editor.IStandaloneCodeEditor;
 | 
			
		||||
 | 
			
		||||
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,
 | 
			
		||||
    modelUri,
 | 
			
		||||
  );
 | 
			
		||||
  var model = monaco.editor.createModel(script.script_body, lang.value);
 | 
			
		||||
 | 
			
		||||
  const theme = $q.dark.isActive ? "vs-dark" : "vs-light";
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -175,6 +175,20 @@
 | 
			
		||||
              >
 | 
			
		||||
                <q-tooltip> Shell </q-tooltip>
 | 
			
		||||
              </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
 | 
			
		||||
@@ -471,6 +485,22 @@
 | 
			
		||||
              >
 | 
			
		||||
                <q-tooltip> Shell </q-tooltip>
 | 
			
		||||
              </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>
 | 
			
		||||
            <!-- supported platforms -->
 | 
			
		||||
            <q-td key="supported_platforms" :props="props">
 | 
			
		||||
 
 | 
			
		||||
@@ -86,6 +86,35 @@ import { notifySuccess } from "@/utils/notify";
 | 
			
		||||
// ui imports
 | 
			
		||||
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
 | 
			
		||||
import type { ScriptSnippet } from "@/types/scripts";
 | 
			
		||||
 | 
			
		||||
@@ -124,11 +153,21 @@ const title = computed(() => {
 | 
			
		||||
 | 
			
		||||
// convert highlighter language to match what ace expects
 | 
			
		||||
const lang = computed(() => {
 | 
			
		||||
  if (snippet.shell === "cmd") return "bat";
 | 
			
		||||
  else if (snippet.shell === "powershell") return "powershell";
 | 
			
		||||
  else if (snippet.shell === "python") return "python";
 | 
			
		||||
  else if (snippet.shell === "shell") return "shell";
 | 
			
		||||
  else return "";
 | 
			
		||||
  switch (snippet.shell) {
 | 
			
		||||
    case "cmd":
 | 
			
		||||
      return "bat";
 | 
			
		||||
    case "powershell":
 | 
			
		||||
      return "powershell";
 | 
			
		||||
    case "python":
 | 
			
		||||
      return "python";
 | 
			
		||||
    case "shell":
 | 
			
		||||
    case "nushell":
 | 
			
		||||
      return "shell";
 | 
			
		||||
    case "deno":
 | 
			
		||||
      return "typescript";
 | 
			
		||||
    default:
 | 
			
		||||
      return "";
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
async function submit() {
 | 
			
		||||
@@ -150,8 +189,7 @@ const snippetEditor = ref<HTMLElement | null>(null);
 | 
			
		||||
let editor: monaco.editor.IStandaloneCodeEditor;
 | 
			
		||||
 | 
			
		||||
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, modelUri);
 | 
			
		||||
  var model = monaco.editor.createModel(snippet.code, lang.value);
 | 
			
		||||
 | 
			
		||||
  const theme = $q.dark.isActive ? "vs-dark" : "vs-light";
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -124,6 +124,22 @@
 | 
			
		||||
              >
 | 
			
		||||
                <q-tooltip> Shell </q-tooltip>
 | 
			
		||||
              </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>
 | 
			
		||||
            <!-- name -->
 | 
			
		||||
            <q-td>{{ props.row.name }}</q-td>
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ export function useScriptDropdown(setScript = null, { onMount = false } = {}) {
 | 
			
		||||
  // specify parameters to filter out community scripts
 | 
			
		||||
  async function getScriptOptions(showCommunityScripts = false) {
 | 
			
		||||
    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], () => {
 | 
			
		||||
    if (script.value && scriptOptions.value.length > 0) {
 | 
			
		||||
      const tmpScript = scriptOptions.value.find(
 | 
			
		||||
        (i) => i.value === script.value
 | 
			
		||||
        (i) => i.value === script.value,
 | 
			
		||||
      );
 | 
			
		||||
      defaultTimeout.value = tmpScript.timeout;
 | 
			
		||||
      defaultArgs.value = tmpScript.args;
 | 
			
		||||
@@ -65,4 +65,6 @@ export const shellOptions = [
 | 
			
		||||
  { label: "Batch", value: "cmd" },
 | 
			
		||||
  { label: "Python", value: "python" },
 | 
			
		||||
  { label: "Shell", value: "shell" },
 | 
			
		||||
  { label: "Nushell", value: "nushell" },
 | 
			
		||||
  { label: "Deno", value: "deno" },
 | 
			
		||||
];
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
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 {
 | 
			
		||||
  id?: number;
 | 
			
		||||
 
 | 
			
		||||
@@ -53,6 +53,26 @@
 | 
			
		||||
                :options="allTimezones"
 | 
			
		||||
              />
 | 
			
		||||
            </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-btn
 | 
			
		||||
                label="Finish"
 | 
			
		||||
@@ -86,6 +106,7 @@ export default {
 | 
			
		||||
      allTimezones: [],
 | 
			
		||||
      timezone: null,
 | 
			
		||||
      arch: "64",
 | 
			
		||||
      companyname: "",
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
@@ -95,6 +116,7 @@ export default {
 | 
			
		||||
        client: this.client,
 | 
			
		||||
        site: this.site,
 | 
			
		||||
        timezone: this.timezone,
 | 
			
		||||
        companyname: this.companyname,
 | 
			
		||||
        initialsetup: true,
 | 
			
		||||
      };
 | 
			
		||||
      this.$axios
 | 
			
		||||
 
 | 
			
		||||
@@ -90,7 +90,7 @@ export default {
 | 
			
		||||
        control.value = data.control;
 | 
			
		||||
        status.value = data.status;
 | 
			
		||||
        useMeta({
 | 
			
		||||
          title: `${data.hostname} - ${data.client} - ${data.site} | Remote Background`,
 | 
			
		||||
          title: `${data.hostname} - ${data.client} - ${data.site} | Take Control`,
 | 
			
		||||
        });
 | 
			
		||||
      } catch (e) {
 | 
			
		||||
        console.error(e);
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user