Compare commits

..

42 Commits

Author SHA1 Message Date
wh1te909
5114ff40aa Release 0.101.35 2023-11-07 17:25:24 +00:00
wh1te909
908b337797 bump version 2023-11-07 17:24:22 +00:00
wh1te909
fea5258903 update deps 2023-11-07 17:23:25 +00:00
Dan
5521e4ea3e Merge pull request #13 from silversword411/develop
Increase name field to show 50chars
2023-11-06 13:07:24 -08:00
silversword411
6cc01596cb Increase name field to show 50chars 2023-11-06 12:14:35 -05:00
sadnub
0694538482 fix editors not closing properly on Escape key press 2023-11-04 23:56:22 -04:00
wh1te909
6ea7c92b20 Release 0.101.34 2023-10-31 17:51:19 +00:00
wh1te909
ac05ad40c0 bump version 2023-10-31 17:50:59 +00:00
wh1te909
239b0182fb add some icons 2023-10-31 07:12:54 +00:00
sadnub
4c57e5da4b put shared template scripts in ascending order 2023-10-29 15:47:27 -04:00
wh1te909
298d039028 remove ace 2023-10-29 19:33:04 +00:00
sadnub
021a066074 watch for language changes and update the snippet editor 2023-10-29 15:16:54 -04:00
sadnub
7dc2f5a658 watch for language changes and update the editor 2023-10-29 15:05:51 -04:00
sadnub
57bd8bafac exported templates now are readable with spaces 2023-10-29 10:55:07 -04:00
sadnub
7d5216aba9 prevent linux shebang banner opening and closing on script load 2023-10-29 10:31:51 -04:00
sadnub
076ab0c465 fix script body not loading in editor. Fix slow unload times for monaco editor 2023-10-29 10:24:16 -04:00
wh1te909
be37e89e16 update reqs 2023-10-29 09:08:02 +00:00
wh1te909
0bdc841084 change wording 2023-10-29 08:57:53 +00:00
wh1te909
96086d0b5d fix wording 2023-10-28 22:06:52 +00:00
wh1te909
20d534eab0 Release 0.101.31 2023-10-01 17:36:52 +00:00
wh1te909
1b2286c4f8 Release 0.101.30 2023-09-30 21:59:09 +00:00
wh1te909
8207f30234 Release 0.101.29 2023-08-30 04:10:11 +00:00
wh1te909
68036f6837 Release 0.101.28 2023-08-14 06:39:49 +00:00
wh1te909
03fae45ac5 Release 0.101.25 2023-07-04 18:49:46 +00:00
wh1te909
c2591c9e7d Release 0.101.22 2023-05-30 22:11:30 +00:00
wh1te909
7fcbe6fbd8 Release 0.101.20 2023-05-09 21:09:45 +00:00
wh1te909
a2f472ef9c Release 0.101.18 2023-04-09 03:28:23 +00:00
wh1te909
8403ac0e93 Release 0.101.16 2023-03-22 17:00:29 +00:00
wh1te909
b7a91563b0 Release 0.101.13 2023-01-18 20:05:20 +00:00
wh1te909
ab19afca16 Release 0.101.11 2022-12-21 18:44:46 +00:00
wh1te909
f24c6a7a80 Release 0.101.9 2022-12-04 23:01:59 +00:00
wh1te909
99490bf859 Release 0.101.7 2022-11-13 01:20:33 +00:00
wh1te909
72cdeeaa6a Release 0.101.5 2022-10-25 22:02:34 +00:00
wh1te909
1eca4d605b Release 0.101.3 2022-10-19 22:35:54 +00:00
wh1te909
52ee98f6f8 Release 0.101.0 2022-09-24 02:43:53 +00:00
wh1te909
d270b877c9 Release 0.100.9 2022-08-23 05:04:57 +00:00
wh1te909
fd8b2a1d98 Release 0.100.8 2022-08-09 20:40:48 +00:00
wh1te909
f518043d8d Release 0.100.7 2022-08-01 17:36:11 +00:00
wh1te909
cc2335558d Release 0.100.6 2022-07-27 06:15:49 +00:00
wh1te909
a8a171ba2c Release 0.100.5 2022-07-10 00:00:08 +00:00
wh1te909
24a63f477e Release 0.100.4 2022-07-07 16:38:14 +00:00
wh1te909
ddeb6293a1 init 2022-05-17 20:46:22 +00:00
10 changed files with 490 additions and 5483 deletions

5794
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{ {
"name": "web", "name": "web",
"version": "0.101.32", "version": "0.101.35",
"private": true, "private": true,
"productName": "Tactical RMM", "productName": "Tactical RMM",
"scripts": { "scripts": {
@@ -11,13 +11,12 @@
}, },
"dependencies": { "dependencies": {
"@quasar/extras": "1.16.7", "@quasar/extras": "1.16.7",
"apexcharts": "3.41.1", "apexcharts": "3.44.0",
"axios": "1.5.1", "axios": "1.6.0",
"dotenv": "16.3.1", "dotenv": "16.3.1",
"qrcode.vue": "3.4.1", "qrcode.vue": "3.4.1",
"quasar": "2.13.0", "quasar": "2.13.0",
"vue": "3.3.7", "vue": "3.3.8",
"vue3-ace-editor": "2.2.3",
"vue3-apexcharts": "1.4.4", "vue3-apexcharts": "1.4.4",
"vuedraggable": "4.1.0", "vuedraggable": "4.1.0",
"vue-router": "4.2.5", "vue-router": "4.2.5",
@@ -25,17 +24,17 @@
"@vueuse/shared": "10.5.0", "@vueuse/shared": "10.5.0",
"monaco-editor": "0.44.0", "monaco-editor": "0.44.0",
"vuex": "4.1.0", "vuex": "4.1.0",
"yaml": "2.3.3" "yaml": "2.3.4"
}, },
"devDependencies": { "devDependencies": {
"@quasar/cli": "2.3.0", "@quasar/cli": "2.3.0",
"@intlify/unplugin-vue-i18n": "1.4.0", "@intlify/unplugin-vue-i18n": "1.4.0",
"@quasar/app-vite": "1.6.2", "@quasar/app-vite": "1.6.2",
"@types/node": "20.8.8", "@types/node": "20.8.10",
"@typescript-eslint/eslint-plugin": "6.9.0", "@typescript-eslint/eslint-plugin": "6.10.0",
"@typescript-eslint/parser": "6.9.0", "@typescript-eslint/parser": "6.10.0",
"autoprefixer": "10.4.16", "autoprefixer": "10.4.16",
"eslint": "8.52.0", "eslint": "8.53.0",
"eslint-config-prettier": "9.0.0", "eslint-config-prettier": "9.0.0",
"eslint-plugin-vue": "8.7.1", "eslint-plugin-vue": "8.7.1",
"prettier": "3.0.3", "prettier": "3.0.3",

View File

@@ -150,7 +150,7 @@
</q-menu> </q-menu>
</q-btn> </q-btn>
<!-- integrations --> <!-- integrations -->
<q-btn size="md" dense no-caps flat label="Integrations"> <q-btn size="md" dense no-caps flat label="Reporting">
<q-menu auto-close> <q-menu auto-close>
<q-list <q-list
v-if=" v-if="

View File

@@ -1,17 +1,12 @@
<template> <template>
<q-dialog <q-dialog
ref="dialogRef" ref="dialogRef"
persistent maximized
@keydown.esc.stop="onDialogHide" @hide="onDialogHide"
:maximized="maximized"
@keydown.esc="unloadEditor"
@hide="unloadEditor"
@show="loadEditor" @show="loadEditor"
@before-hide="unloadEditor"
> >
<q-card <q-card class="q-dialog-plugin">
class="q-dialog-plugin"
:style="maximized ? '' : 'width: 90vw; max-width: 90vw'"
>
<q-bar> <q-bar>
<span class="q-pr-sm">{{ title }}</span> <span class="q-pr-sm">{{ title }}</span>
<q-btn <q-btn
@@ -25,34 +20,12 @@
@click="generateScriptOpenAI" @click="generateScriptOpenAI"
/> />
<q-space /> <q-space />
<q-btn
dense
flat
icon="minimize"
@click="maximized = false"
:disable="!maximized"
>
<q-tooltip v-if="maximized" class="bg-white text-primary"
>Minimize</q-tooltip
>
</q-btn>
<q-btn
dense
flat
icon="crop_square"
@click="maximized = true"
:disable="maximized"
>
<q-tooltip v-if="!maximized" class="bg-white text-primary"
>Maximize</q-tooltip
>
</q-btn>
<q-btn dense flat icon="close" v-close-popup> <q-btn dense flat icon="close" v-close-popup>
<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-banner <q-banner
v-if="missingShebang" v-if="script.script_body && missingShebang"
dense dense
inline-actions inline-actions
class="text-black bg-warning" class="text-black bg-warning"
@@ -78,7 +51,7 @@
opacity: '0.2', opacity: '0.2',
}" }"
class="col-4 q-mb-none q-pb-none" class="col-4 q-mb-none q-pb-none"
:style="{ height: `${maximized ? '82vh' : '64vh'}` }" :style="{ height: `${$q.screen.height - 106}px` }"
> >
<div class="q-gutter-sm q-pr-sm"> <div class="q-gutter-sm q-pr-sm">
<q-input <q-input
@@ -170,8 +143,7 @@
>Setting this value on the script model will always override any >Setting this value on the script model will always override any
'Run As User' checkboxes in the UI and force this script to 'Run As User' checkboxes in the UI and force this script to
always be run in the context of the logged in user. If no user always be run in the context of the logged in user. If no user
is logged in, the script will not run and an error will be is logged in, the script will run as SYSTEM.
returned.
</q-tooltip> </q-tooltip>
</q-checkbox> </q-checkbox>
<q-input <q-input
@@ -188,7 +160,7 @@
<div <div
ref="scriptEditor" ref="scriptEditor"
class="col-8 q-mb-none q-pb-none" class="col-8 q-mb-none q-pb-none"
:style="{ height: `${maximized ? '82vh' : '64vh'}` }" :style="{ height: `${$q.screen.height - 106}px` }"
></div> ></div>
</div> </div>
<q-card-actions> <q-card-actions>
@@ -235,7 +207,7 @@
<script setup lang="ts"> <script setup lang="ts">
// composable imports // composable imports
import { ref, reactive, computed, onMounted } from "vue"; import { ref, reactive, watch, computed, onMounted } from "vue";
import { useStore } from "vuex"; import { useStore } from "vuex";
import { useQuasar, useDialogPluginComponent } from "quasar"; import { useQuasar, useDialogPluginComponent } from "quasar";
import { saveScript, editScript, downloadScript } from "@/api/scripts"; import { saveScript, editScript, downloadScript } from "@/api/scripts";
@@ -266,7 +238,7 @@ const props = withDefaults(
{ {
clone: false, clone: false,
readonly: false, readonly: false,
} },
); );
// emits // emits
@@ -297,7 +269,6 @@ const script: Script = props.script
}); });
if (props.clone) script.name = `(Copy) ${script.name}`; if (props.clone) script.name = `(Copy) ${script.name}`;
const maximized = ref(false);
const loading = ref(false); const loading = ref(false);
const agentLoading = ref(false); const agentLoading = ref(false);
@@ -330,12 +301,6 @@ const lang = computed(() => {
else return ""; else return "";
}); });
// get code if editing or cloning script
if (props.script)
downloadScript(script.id, { with_snippets: props.readonly }).then((r) => {
script.script_body = r.code;
});
async function submit() { async function submit() {
loading.value = true; loading.value = true;
let result = ""; let result = "";
@@ -376,7 +341,7 @@ function loadEditor() {
var model = monaco.editor.createModel( var model = monaco.editor.createModel(
script.script_body, script.script_body,
lang.value, lang.value,
modelUri modelUri,
); );
const theme = $q.dark.isActive ? "vs-dark" : "vs-light"; const theme = $q.dark.isActive ? "vs-dark" : "vs-light";
@@ -392,6 +357,18 @@ function loadEditor() {
editor.onDidChangeModelContent(() => { editor.onDidChangeModelContent(() => {
script.script_body = editor.getValue(); script.script_body = editor.getValue();
}); });
// get code if editing or cloning script
if (props.script)
downloadScript(script.id, { with_snippets: props.readonly }).then((r) => {
script.script_body = r.code;
editor.setValue(r.code);
});
// watch for changes in language
watch(lang, () => {
monaco.editor.setModelLanguage(model, lang.value);
});
} }
function unloadEditor() { function unloadEditor() {

View File

@@ -1,16 +1,12 @@
<template> <template>
<q-dialog <q-dialog
ref="dialogRef" ref="dialogRef"
persistent maximized
@keydown.esc="unloadEditor" @hide="onDialogHide"
:maximized="maximized"
@hide="unloadEditor"
@show="loadEditor" @show="loadEditor"
@before-hide="unloadEditor"
> >
<q-card <q-card class="q-dialog-plugin">
class="q-dialog-plugin"
:style="maximized ? '' : 'width: 70vw; max-width: 90vw'"
>
<q-bar> <q-bar>
<span class="q-pr-sm">{{ title }}</span> <span class="q-pr-sm">{{ title }}</span>
<q-btn <q-btn
@@ -24,35 +20,13 @@
@click="generateScriptOpenAI" @click="generateScriptOpenAI"
/> />
<q-space /> <q-space />
<q-btn
dense
flat
icon="minimize"
@click="maximized = false"
:disable="!maximized"
>
<q-tooltip v-if="maximized" class="bg-white text-primary"
>Minimize</q-tooltip
>
</q-btn>
<q-btn
dense
flat
icon="crop_square"
@click="maximized = true"
:disable="maximized"
>
<q-tooltip v-if="!maximized" class="bg-white text-primary"
>Maximize</q-tooltip
>
</q-btn>
<q-btn dense flat icon="close" v-close-popup> <q-btn dense flat icon="close" v-close-popup>
<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>
<div class="row"> <div class="row">
<q-input <q-input
:rules="[(val) => !!val || '*Required']" :rules="[(val: string) => !!val || '*Required']"
class="q-pa-sm col-4" class="q-pa-sm col-4"
v-model="snippet.name" v-model="snippet.name"
label="Name" label="Name"
@@ -81,7 +55,7 @@
<div <div
ref="snippetEditor" ref="snippetEditor"
:style="{ height: `${maximized ? '82vh' : '64vh'}` }" :style="{ height: `${$q.screen.height - 132}px` }"
></div> ></div>
<q-card-actions align="right"> <q-card-actions align="right">
@@ -101,7 +75,7 @@
<script setup lang="ts"> <script setup lang="ts">
// composable imports // composable imports
import { ref, reactive, computed } from "vue"; import { ref, watch, reactive, computed } from "vue";
import { useStore } from "vuex"; import { useStore } from "vuex";
import { useQuasar } from "quasar"; import { useQuasar } from "quasar";
import { generateScript } from "@/api/core"; import { generateScript } from "@/api/core";
@@ -138,7 +112,6 @@ const openAIEnabled = computed(() => store.state.openAIIntegrationEnabled);
const snippet: ScriptSnippet = props.snippet const snippet: ScriptSnippet = props.snippet
? reactive(Object.assign({}, props.snippet)) ? reactive(Object.assign({}, props.snippet))
: reactive({ name: "", code: "", shell: "powershell" }); : reactive({ name: "", code: "", shell: "powershell" });
const maximized = ref(false);
const loading = ref(false); const loading = ref(false);
const title = computed(() => { const title = computed(() => {
@@ -177,7 +150,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://new"); // a made up unique URI for our model 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, modelUri);
const theme = $q.dark.isActive ? "vs-dark" : "vs-light"; const theme = $q.dark.isActive ? "vs-dark" : "vs-light";
@@ -192,6 +165,11 @@ function loadEditor() {
editor.onDidChangeModelContent(() => { editor.onDidChangeModelContent(() => {
snippet.code = editor.getValue(); snippet.code = editor.getValue();
}); });
// watch for changes in language
watch(lang, () => {
monaco.editor.setModelLanguage(model, lang.value);
});
} }
function unloadEditor() { function unloadEditor() {

View File

@@ -302,7 +302,10 @@ export function useReportTemplates(): useReportingTemplates {
axios axios
.post(`${baseUrl}/templates/${id}/export/`) .post(`${baseUrl}/templates/${id}/export/`)
.then(({ data }) => { .then(({ data }) => {
exportFile(`${data.template.name}-export.json`, JSON.stringify(data)); exportFile(
`${data.template.name}-export.json`,
JSON.stringify(data, null, 2),
);
}) })
.catch(() => (isError.value = true)) .catch(() => (isError.value = true))
.finally(() => (isLoading.value = false)); .finally(() => (isLoading.value = false));

View File

@@ -34,7 +34,7 @@ For details, see: https://license.tacticalrmm.com/ee
class="q-pr-sm" class="q-pr-sm"
filled filled
dense dense
style="width: 250px" style="width: 425px"
:error="!isNameValid" :error="!isNameValid"
hide-bottom-space hide-bottom-space
/> />

View File

@@ -54,6 +54,9 @@ For details, see: https://license.tacticalrmm.com/ee
clickable clickable
@click="openNewReportTemplateForm('markdown')" @click="openNewReportTemplateForm('markdown')"
> >
<q-item-section avatar>
<q-icon name="fa-brands fa-markdown" />
</q-item-section>
<q-item-section> <q-item-section>
<q-item-label>Markdown Template</q-item-label> <q-item-label>Markdown Template</q-item-label>
</q-item-section> </q-item-section>
@@ -64,8 +67,11 @@ For details, see: https://license.tacticalrmm.com/ee
clickable clickable
@click="openNewReportTemplateForm('html')" @click="openNewReportTemplateForm('html')"
> >
<q-item-section avatar>
<q-icon name="fa-brands fa-html5" />
</q-item-section>
<q-item-section> <q-item-section>
<q-item-label>Html Template</q-item-label> <q-item-label>HTML Template</q-item-label>
</q-item-section> </q-item-section>
</q-item> </q-item>
@@ -74,6 +80,9 @@ For details, see: https://license.tacticalrmm.com/ee
clickable clickable
@click="openNewReportTemplateForm('plaintext')" @click="openNewReportTemplateForm('plaintext')"
> >
<q-item-section avatar>
<q-icon name="fa-solid fa-file-csv" />
</q-item-section>
<q-item-section> <q-item-section>
<q-item-label>Plain Text Template</q-item-label> <q-item-label>Plain Text Template</q-item-label>
</q-item-section> </q-item-section>
@@ -82,6 +91,9 @@ For details, see: https://license.tacticalrmm.com/ee
<q-separator /> <q-separator />
<q-item clickable v-close-popup @click="importReportTemplate"> <q-item clickable v-close-popup @click="importReportTemplate">
<q-item-section avatar>
<q-icon name="fa-solid fa-file-import" />
</q-item-section>
<q-item-section> <q-item-section>
<q-item-label>Import Report Template</q-item-label> <q-item-label>Import Report Template</q-item-label>
</q-item-section> </q-item-section>
@@ -91,6 +103,7 @@ For details, see: https://license.tacticalrmm.com/ee
<q-btn <q-btn
class="q-ml-sm" class="q-ml-sm"
label="Base Templates" label="Base Templates"
icon="fa-regular fa-file-code"
no-caps no-caps
dense dense
flat flat
@@ -99,6 +112,7 @@ For details, see: https://license.tacticalrmm.com/ee
<q-btn <q-btn
class="q-ml-sm" class="q-ml-sm"
label="Report Assets" label="Report Assets"
icon="fa-regular fa-folder-closed"
no-caps no-caps
dense dense
flat flat
@@ -107,6 +121,7 @@ For details, see: https://license.tacticalrmm.com/ee
<q-btn <q-btn
class="q-ml-sm" class="q-ml-sm"
label="Data Queries" label="Data Queries"
icon="fa-solid fa-database"
no-caps no-caps
dense dense
flat flat
@@ -115,6 +130,7 @@ For details, see: https://license.tacticalrmm.com/ee
<q-btn <q-btn
class="q-ml-sm" class="q-ml-sm"
label="Shared Templates" label="Shared Templates"
icon="fa-solid fa-share"
no-caps no-caps
dense dense
flat flat

View File

@@ -25,7 +25,7 @@ For details, see: https://license.tacticalrmm.com/ee
:rows="sharedTemplates" :rows="sharedTemplates"
: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"
selection="multiple" selection="multiple"
v-model:selected="selected" v-model:selected="selected"

View File

@@ -13,7 +13,11 @@
> >
<q-spinner size="40px" color="primary" /> <q-spinner size="40px" color="primary" />
</div> </div>
<div v-else class="q-pa-sm q-gutter-sm scroll" style="height: 85vh; overflow: initial;"> <div
v-else
class="q-pa-sm q-gutter-sm scroll"
style="height: 85vh; overflow: initial"
>
<q-list dense class="rounded-borders"> <q-list dense class="rounded-borders">
<q-item <q-item
clickable clickable
@@ -163,7 +167,7 @@
runURLAction( runURLAction(
props.node.id, props.node.id,
action.id, action.id,
props.node.children ? 'client' : 'site' props.node.children ? 'client' : 'site',
) )
" "
> >
@@ -196,9 +200,9 @@
" "
> >
<q-item-section side> <q-item-section side>
<q-icon name="integration_instructions" /> <q-icon 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>
@@ -816,7 +820,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;
} }