Compare commits

..

23 Commits

Author SHA1 Message Date
wh1te909
7fcbe6fbd8 Release 0.101.20 2023-05-09 21:09:45 +00:00
wh1te909
0113fbc761 hide openai until next release 2023-05-09 21:06:40 +00:00
wh1te909
95df8c1889 update reqs 2023-05-07 02:16:19 +00:00
sadnub
819a364207 Merge pull request #8 from sadnub/develop
open ai integration
2023-04-10 19:06:18 -04:00
sadnub
ed2b07fb0b change wording on default prompt 2023-04-10 19:04:01 -04:00
sadnub
64ed5e8740 open ai integration 2023-04-09 22:36:20 -04:00
wh1te909
a2f472ef9c Release 0.101.18 2023-04-09 03:28:23 +00:00
wh1te909
cdeaa3d9c4 bump version 2023-04-09 03:28:00 +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
7 changed files with 1155 additions and 505 deletions

1274
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.17-dev", "version": "0.101.20",
"private": true, "private": true,
"productName": "Tactical RMM", "productName": "Tactical RMM",
"scripts": { "scripts": {
@@ -10,12 +10,12 @@
"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.2", "@quasar/extras": "1.16.3",
"apexcharts": "3.37.3", "apexcharts": "3.40.0",
"axios": "1.3.5", "axios": "1.4.0",
"dotenv": "16.0.3", "dotenv": "16.0.3",
"qrcode.vue": "3.3.4", "qrcode.vue": "3.3.4",
"quasar": "2.11.10", "quasar": "2.12.0",
"vue": "3.2.47", "vue": "3.2.47",
"vue3-ace-editor": "2.2.2", "vue3-ace-editor": "2.2.2",
"vue3-apexcharts": "1.4.1", "vue3-apexcharts": "1.4.1",
@@ -24,17 +24,17 @@
"vuex": "4.1.0" "vuex": "4.1.0"
}, },
"devDependencies": { "devDependencies": {
"@quasar/cli": "^2.0.0", "@quasar/cli": "^2.1.0",
"@intlify/unplugin-vue-i18n": "^0.10.0", "@intlify/unplugin-vue-i18n": "^0.10.0",
"@quasar/app-vite": "^1.2.1", "@quasar/app-vite": "^1.3.0",
"@types/node": "^18.15.11", "@types/node": "^18.16.5",
"@typescript-eslint/eslint-plugin": "^5.57.1", "@typescript-eslint/eslint-plugin": "^5.59.2",
"@typescript-eslint/parser": "^5.57.1", "@typescript-eslint/parser": "^5.59.2",
"autoprefixer": "10.4.14", "autoprefixer": "10.4.14",
"eslint": "8.37.0", "eslint": "8.40.0",
"eslint-config-prettier": "8.8.0", "eslint-config-prettier": "8.8.0",
"eslint-plugin-vue": "8.7.1", "eslint-plugin-vue": "8.7.1",
"prettier": "2.8.7", "prettier": "2.8.8",
"typescript": "5.0.4" "typescript": "5.0.4"
} }
} }

View File

@@ -38,3 +38,8 @@ export async function runURLAction(payload) {
console.error(e); console.error(e);
} }
} }
export async function generateScript(payload) {
const { data } = await axios.post(`${baseUrl}/openai/generate/`, payload);
return data;
}

View File

@@ -12,6 +12,7 @@
<q-tab name="urlactions" label="URL Actions" /> <q-tab name="urlactions" label="URL Actions" />
<q-tab name="retention" label="Retention" /> <q-tab name="retention" label="Retention" />
<q-tab name="apikeys" label="API Keys" /> <q-tab name="apikeys" label="API Keys" />
<!-- <q-tab name="openai" label="Open AI" /> -->
</q-tabs> </q-tabs>
</template> </template>
<template v-slot:after> <template v-slot:after>
@@ -508,6 +509,49 @@
<q-tab-panel name="apikeys"> <q-tab-panel name="apikeys">
<APIKeysTable /> <APIKeysTable />
</q-tab-panel> </q-tab-panel>
<!-- Open AI -->
<!-- <q-tab-panel name="openai">
<div class="text-subtitle2">Open AI</div>
<q-separator />
<q-card-section class="row">
<div class="col-4">API Key:</div>
<div class="col-2"></div>
<q-input
dense
outlined
v-model="settings.open_ai_token"
class="col-6"
/>
</q-card-section>
<q-card-section class="row">
<div class="col-4">Open AI Model:</div>
<div class="col-2"></div>
<q-input
dense
outlined
v-model="settings.open_ai_model"
class="col-6"
>
<template v-slot:after>
<q-btn
round
dense
flat
icon="info"
size="sm"
@click="
openURL(
'https://platform.openai.com/docs/models/overview'
)
"
>
<q-tooltip>Click to see available options</q-tooltip>
</q-btn>
</template>
</q-input>
</q-card-section>
</q-tab-panel> -->
</q-tab-panels> </q-tab-panels>
</q-scroll-area> </q-scroll-area>
<q-card-section class="row items-center"> <q-card-section class="row items-center">

View File

@@ -11,7 +11,17 @@
:style="maximized ? '' : 'width: 90vw; max-width: 90vw'" :style="maximized ? '' : 'width: 90vw; max-width: 90vw'"
> >
<q-bar> <q-bar>
{{ title }} <span class="q-pr-sm">{{ title }}</span>
<q-btn
v-if="!script && openAIEnabled"
size="xs"
:disable="loading"
dense
label="Generate Script"
color="primary"
no-caps
@click="generateScriptOpenAI"
/>
<q-space /> <q-space />
<q-btn <q-btn
dense dense
@@ -57,116 +67,133 @@
><br />Add one to get rid of this warning. Ignore if windows. ><br />Add one to get rid of this warning. Ignore if windows.
</q-banner> </q-banner>
<div class="row q-pa-sm"> <div class="row q-pa-sm">
<div class="col-4 q-gutter-sm q-pr-sm"> <q-scroll-area
<q-input :thumb-style="{
filled right: '4px',
dense borderRadius: '5px',
:readonly="readonly" width: '5px',
v-model="formScript.name" opacity: 0.75,
label="Name" }"
:rules="[(val) => !!val || '*Required']" :bar-style="{
hide-bottom-space right: '2px',
/> borderRadius: '9px',
<q-input width: '9px',
filled opacity: 0.2,
dense }"
:readonly="readonly" class="col-4 q-mb-none q-pb-none"
v-model="formScript.description" :style="{ height: `${maximized ? '82vh' : '64vh'}` }"
label="Description" >
/> <div class="q-gutter-sm q-pr-sm">
<q-select <q-input
:readonly="readonly" filled
options-dense dense
filled :readonly="readonly"
dense v-model="formScript.name"
v-model="formScript.shell" label="Name"
:options="shellOptions" :rules="[(val) => !!val || '*Required']"
emit-value hide-bottom-space
map-options />
label="Shell Type" <q-input
/> filled
<tactical-dropdown dense
v-model="formScript.supported_platforms" :readonly="readonly"
:options="agentPlatformOptions" v-model="formScript.description"
label="Supported Platforms (All supported if blank)" label="Description"
clearable />
mapOptions <q-select
filled :readonly="readonly"
multiple options-dense
:readonly="readonly" filled
/> dense
<tactical-dropdown v-model="formScript.shell"
filled :options="shellOptions"
v-model="formScript.category" emit-value
:options="categories" map-options
use-input label="Shell Type"
clearable />
new-value-mode="add-unique" <tactical-dropdown
filterable v-model="formScript.supported_platforms"
label="Category" :options="agentPlatformOptions"
:readonly="readonly" label="Supported Platforms (All supported if blank)"
hide-bottom-space clearable
/> mapOptions
<tactical-dropdown filled
v-model="formScript.args" multiple
label="Script Arguments (press Enter after typing each argument)" :readonly="readonly"
filled />
use-input <tactical-dropdown
multiple filled
hide-dropdown-icon v-model="formScript.category"
input-debounce="0" :options="categories"
new-value-mode="add" use-input
:readonly="readonly" clearable
/> new-value-mode="add-unique"
<tactical-dropdown filterable
v-model="formScript.env_vars" label="Category"
:label="envVarsLabel" :readonly="readonly"
filled hide-bottom-space
use-input />
multiple <tactical-dropdown
hide-dropdown-icon v-model="formScript.args"
input-debounce="0" label="Script Arguments (press Enter after typing each argument)"
new-value-mode="add" filled
:readonly="readonly" use-input
/> multiple
<q-input hide-dropdown-icon
type="number" input-debounce="0"
filled new-value-mode="add"
dense :readonly="readonly"
:readonly="readonly" />
v-model.number="formScript.default_timeout" <tactical-dropdown
label="Timeout (seconds)" v-model="formScript.env_vars"
:rules="[(val) => val >= 5 || 'Minimum is 5']" :label="envVarsLabel"
hide-bottom-space filled
/> use-input
<q-checkbox multiple
v-model="formScript.run_as_user" hide-dropdown-icon
label="Run As User (Windows only)" input-debounce="0"
> new-value-mode="add"
<q-tooltip :readonly="readonly"
>Setting this value on the script model will always override any />
'Run As User' checkboxes in the UI and force this script to <q-input
always be run in the context of the logged in user. If no user type="number"
is logged in, the script will not run and an error will be filled
returned. dense
</q-tooltip> :readonly="readonly"
</q-checkbox> v-model.number="formScript.default_timeout"
<q-input label="Timeout (seconds)"
label="Syntax" :rules="[(val) => val >= 5 || 'Minimum is 5']"
type="textarea" hide-bottom-space
style="height: 150px; overflow-y: auto; resize: none" />
v-model="formScript.syntax" <q-checkbox
dense v-model="formScript.run_as_user"
filled label="Run As User (Windows only)"
:readonly="readonly" >
/> <q-tooltip
</div> >Setting this value on the script model will always override
any '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 is logged in, the script will not run and an error will
be returned.
</q-tooltip>
</q-checkbox>
<q-input
label="Syntax"
type="textarea"
style="height: 150px; overflow-y: auto; resize: none"
v-model="formScript.syntax"
dense
filled
:readonly="readonly"
/>
</div>
</q-scroll-area>
<v-ace-editor <v-ace-editor
v-model:value="formScript.script_body" v-model:value="formScript.script_body"
class="col-8" class="col-8"
:lang="lang" :lang="lang"
:theme="$q.dark.isActive ? 'tomorrow_night_eighties' : 'tomorrow'" :theme="$q.dark.isActive ? 'tomorrow_night_eighties' : 'tomorrow'"
:style="{ height: `${maximized ? '87vh' : '64vh'}` }" :style="{ height: `${maximized ? '82vh' : '64vh'}` }"
wrap wrap
:printMargin="false" :printMargin="false"
:options="{ fontSize: '14px' }" :options="{ fontSize: '14px' }"
@@ -220,9 +247,11 @@
<script> <script>
// composable imports // composable imports
import { ref, computed, onMounted } from "vue"; import { ref, computed, onMounted } from "vue";
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";
import { useAgentDropdown, agentPlatformOptions } from "@/composables/agents"; import { useAgentDropdown, agentPlatformOptions } from "@/composables/agents";
import { generateScript } from "@/api/core";
import { notifySuccess } from "@/utils/notify"; import { notifySuccess } from "@/utils/notify";
// ui imports // ui imports
@@ -266,6 +295,10 @@ export default {
const { dialogRef, onDialogHide, onDialogOK } = useDialogPluginComponent(); const { dialogRef, onDialogHide, onDialogOK } = useDialogPluginComponent();
const $q = useQuasar(); const $q = useQuasar();
// setup store
const store = useStore();
const openAIEnabled = computed(() => store.state.openAIIntegrationEnabled);
// setup agent dropdown // setup agent dropdown
const { agent, agentOptions, getAgentOptions } = useAgentDropdown(); const { agent, agentOptions, getAgentOptions } = useAgentDropdown();
@@ -355,6 +388,23 @@ export default {
}); });
} }
function generateScriptOpenAI() {
$q.dialog({
title: "Ask ChatGPT what you need!",
prompt: {
model: `${lang.value} code that `,
type: "text",
},
cancel: true,
persistent: true,
}).onOk(async (data) => {
const completion = await generateScript({
prompt: data,
});
script.value.script_body = completion;
});
}
// component life cycle hooks // component life cycle hooks
onMounted(async () => { onMounted(async () => {
agentLoading.value = true; agentLoading.value = true;
@@ -380,10 +430,12 @@ export default {
//computed //computed
title, title,
openAIEnabled,
//methods //methods
submitForm, submitForm,
openTestScriptModal, openTestScriptModal,
generateScriptOpenAI,
// quasar dialog plugin // quasar dialog plugin
dialogRef, dialogRef,

View File

@@ -11,7 +11,17 @@
:style="maximized ? '' : 'width: 70vw; max-width: 90vw'" :style="maximized ? '' : 'width: 70vw; max-width: 90vw'"
> >
<q-bar> <q-bar>
{{ title }} <span class="q-pr-sm">{{ title }}</span>
<q-btn
v-if="!snippet && openAIEnabled"
:disable="loading"
dense
size="xs"
label="Generate Script"
color="primary"
no-caps
@click="generateScriptOpenAI"
/>
<q-space /> <q-space />
<q-btn <q-btn
dense dense
@@ -97,6 +107,9 @@
<script> <script>
// composable imports // composable imports
import { ref, computed } from "vue"; import { ref, computed } from "vue";
import { useStore } from "vuex";
import { useQuasar } from "quasar";
import { generateScript } from "@/api/core";
import { useDialogPluginComponent } from "quasar"; import { useDialogPluginComponent } from "quasar";
import { saveScriptSnippet, editScriptSnippet } from "@/api/scripts"; import { saveScriptSnippet, editScriptSnippet } from "@/api/scripts";
import { notifySuccess } from "@/utils/notify"; import { notifySuccess } from "@/utils/notify";
@@ -128,6 +141,13 @@ export default {
// setup quasar plugins // setup quasar plugins
const { dialogRef, onDialogHide, onDialogOK } = useDialogPluginComponent(); const { dialogRef, onDialogHide, onDialogOK } = useDialogPluginComponent();
// setup quasar
const $q = useQuasar();
// setup store
const store = useStore();
const openAIEnabled = computed(() => store.state.openAIIntegrationEnabled);
// snippet form logic // snippet form logic
const snippet = props.snippet const snippet = props.snippet
? ref(Object.assign({}, props.snippet)) ? ref(Object.assign({}, props.snippet))
@@ -167,6 +187,23 @@ export default {
loading.value = false; loading.value = false;
} }
function generateScriptOpenAI() {
$q.dialog({
title: "Ask ChatGPT what you need!",
prompt: {
model: `${lang.value} code that `,
type: "text",
},
cancel: true,
persistent: true,
}).onOk(async (data) => {
const completion = await generateScript({
prompt: data,
});
snippet.value.code = completion;
});
}
return { return {
// reactive data // reactive data
formSnippet: snippet.value, formSnippet: snippet.value,
@@ -179,9 +216,11 @@ export default {
//computed //computed
title, title,
openAIEnabled,
//methods //methods
submitForm, submitForm,
generateScriptOpenAI,
// quasar dialog plugin // quasar dialog plugin
dialogRef, dialogRef,

View File

@@ -33,6 +33,7 @@ export default function () {
currentTRMMVersion: null, currentTRMMVersion: null,
latestTRMMVersion: null, latestTRMMVersion: null,
dateFormat: "MMM-DD-YYYY - HH:mm", dateFormat: "MMM-DD-YYYY - HH:mm",
openAIIntegrationEnabled: false,
}; };
}, },
getters: { getters: {
@@ -136,6 +137,9 @@ export default function () {
setDateFormat(state, val) { setDateFormat(state, val) {
state.dateFormat = val; state.dateFormat = val;
}, },
setOpenAIIntegrationStatus(state, val) {
state.openAIIntegrationEnabled = val;
},
}, },
actions: { actions: {
setClientTreeSplitter(context, val) { setClientTreeSplitter(context, val) {
@@ -217,6 +221,10 @@ export default function () {
context.commit("setShowCommunityScripts", data.show_community_scripts); context.commit("setShowCommunityScripts", data.show_community_scripts);
context.commit("SET_HOSTED", data.hosted); context.commit("SET_HOSTED", data.hosted);
context.commit("SET_TOKEN_EXPIRED", data.token_is_expired); context.commit("SET_TOKEN_EXPIRED", data.token_is_expired);
context.commit(
"setOpenAIIntegrationStatus",
data.open_ai_integration_enabled
);
if (data.date_format && data.date_format !== "") if (data.date_format && data.date_format !== "")
context.commit("setDateFormat", data.date_format); context.commit("setDateFormat", data.date_format);