Compare commits
15 Commits
v0.101.27-
...
v0.101.16
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8403ac0e93 | ||
|
|
b7a91563b0 | ||
|
|
ab19afca16 | ||
|
|
f24c6a7a80 | ||
|
|
99490bf859 | ||
|
|
72cdeeaa6a | ||
|
|
1eca4d605b | ||
|
|
52ee98f6f8 | ||
|
|
d270b877c9 | ||
|
|
fd8b2a1d98 | ||
|
|
f518043d8d | ||
|
|
cc2335558d | ||
|
|
a8a171ba2c | ||
|
|
24a63f477e | ||
|
|
ddeb6293a1 |
3
.github/workflows/build-release.yml
vendored
3
.github/workflows/build-release.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
|
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 16
|
||||||
|
|
||||||
- run: touch env-config.js
|
- run: touch env-config.js
|
||||||
|
|
||||||
@@ -32,3 +32,4 @@ jobs:
|
|||||||
uses: softprops/action-gh-release@v1
|
uses: softprops/action-gh-release@v1
|
||||||
with:
|
with:
|
||||||
files: trmm-web-${{github.ref_name}}.tar.gz
|
files: trmm-web-${{github.ref_name}}.tar.gz
|
||||||
|
|
||||||
|
|||||||
2687
package-lock.json
generated
2687
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
44
package.json
44
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "web",
|
"name": "web",
|
||||||
"version": "0.101.27-dev",
|
"version": "0.101.16",
|
||||||
"private": true,
|
"private": true,
|
||||||
"productName": "Tactical RMM",
|
"productName": "Tactical RMM",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -10,31 +10,31 @@
|
|||||||
"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.5",
|
"@quasar/extras": "1.15.11",
|
||||||
"apexcharts": "3.41.1",
|
"apexcharts": "3.37.1",
|
||||||
"axios": "1.4.0",
|
"axios": "1.3.4",
|
||||||
"dotenv": "16.3.1",
|
"dotenv": "16.0.3",
|
||||||
"qrcode.vue": "3.4.1",
|
"qrcode.vue": "3.3.4",
|
||||||
"quasar": "2.12.4",
|
"quasar": "2.11.8",
|
||||||
"vue": "3.3.4",
|
"vue": "3.2.47",
|
||||||
"vue3-ace-editor": "2.2.3",
|
"vue3-ace-editor": "2.2.2",
|
||||||
"vue3-apexcharts": "1.4.4",
|
"vue3-apexcharts": "1.4.1",
|
||||||
"vuedraggable": "4.1.0",
|
"vuedraggable": "4.1.0",
|
||||||
"vue-router": "4.2.4",
|
"vue-router": "4.1.6",
|
||||||
"vuex": "4.1.0"
|
"vuex": "4.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@quasar/cli": "^2.2.2",
|
"@quasar/cli": "^2.0.0",
|
||||||
"@intlify/unplugin-vue-i18n": "^0.12.2",
|
"@intlify/unplugin-vue-i18n": "^0.9.2",
|
||||||
"@quasar/app-vite": "^1.4.3",
|
"@quasar/app-vite": "^1.2.1",
|
||||||
"@types/node": "^20.4.8",
|
"@types/node": "^18.15.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.2.1",
|
"@typescript-eslint/eslint-plugin": "^5.55.0",
|
||||||
"@typescript-eslint/parser": "^6.2.1",
|
"@typescript-eslint/parser": "^5.55.0",
|
||||||
"autoprefixer": "10.4.14",
|
"autoprefixer": "10.4.14",
|
||||||
"eslint": "8.46.0",
|
"eslint": "8.36.0",
|
||||||
"eslint-config-prettier": "9.0.0",
|
"eslint-config-prettier": "8.7.0",
|
||||||
"eslint-plugin-vue": "8.7.1",
|
"eslint-plugin-vue": "8.7.1",
|
||||||
"prettier": "3.0.1",
|
"prettier": "2.8.4",
|
||||||
"typescript": "5.1.6"
|
"typescript": "4.9.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12,9 +12,6 @@ export default {
|
|||||||
body
|
body
|
||||||
overflow-y: hidden
|
overflow-y: hidden
|
||||||
|
|
||||||
a
|
|
||||||
color: #1976D2
|
|
||||||
|
|
||||||
.tbl-sticky
|
.tbl-sticky
|
||||||
thead tr th
|
thead tr th
|
||||||
position: sticky
|
position: sticky
|
||||||
|
|||||||
@@ -232,8 +232,3 @@ export async function removeAgentNote(pk) {
|
|||||||
const { data } = await axios.delete(`${baseUrl}/notes/${pk}/`);
|
const { data } = await axios.delete(`${baseUrl}/notes/${pk}/`);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function wakeUpWOL(agent_id) {
|
|
||||||
const { data } = await axios.post(`${baseUrl}/${agent_id}/wol/`);
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -38,8 +38,3 @@ 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;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -211,7 +211,7 @@
|
|||||||
v-if="props.row.maintenance_mode"
|
v-if="props.row.maintenance_mode"
|
||||||
name="construction"
|
name="construction"
|
||||||
size="1.2em"
|
size="1.2em"
|
||||||
:color="dash_positive_color"
|
color="green"
|
||||||
>
|
>
|
||||||
<q-tooltip>Maintenance Mode Enabled</q-tooltip>
|
<q-tooltip>Maintenance Mode Enabled</q-tooltip>
|
||||||
</q-icon>
|
</q-icon>
|
||||||
@@ -219,7 +219,7 @@
|
|||||||
v-else-if="props.row.checks.failing > 0"
|
v-else-if="props.row.checks.failing > 0"
|
||||||
name="fas fa-check-double"
|
name="fas fa-check-double"
|
||||||
size="1.2em"
|
size="1.2em"
|
||||||
:color="dash_negative_color"
|
color="negative"
|
||||||
>
|
>
|
||||||
<q-tooltip>Checks failing</q-tooltip>
|
<q-tooltip>Checks failing</q-tooltip>
|
||||||
</q-icon>
|
</q-icon>
|
||||||
@@ -227,7 +227,7 @@
|
|||||||
v-else-if="props.row.checks.warning > 0"
|
v-else-if="props.row.checks.warning > 0"
|
||||||
name="fas fa-check-double"
|
name="fas fa-check-double"
|
||||||
size="1.2em"
|
size="1.2em"
|
||||||
:color="dash_warning_color"
|
color="warning"
|
||||||
>
|
>
|
||||||
<q-tooltip>Checks warning</q-tooltip>
|
<q-tooltip>Checks warning</q-tooltip>
|
||||||
</q-icon>
|
</q-icon>
|
||||||
@@ -235,7 +235,7 @@
|
|||||||
v-else-if="props.row.checks.info > 0"
|
v-else-if="props.row.checks.info > 0"
|
||||||
name="fas fa-check-double"
|
name="fas fa-check-double"
|
||||||
size="1.2em"
|
size="1.2em"
|
||||||
:color="dash_info_color"
|
color="info"
|
||||||
>
|
>
|
||||||
<q-tooltip>Checks info</q-tooltip>
|
<q-tooltip>Checks info</q-tooltip>
|
||||||
</q-icon>
|
</q-icon>
|
||||||
@@ -243,7 +243,7 @@
|
|||||||
v-else
|
v-else
|
||||||
name="fas fa-check-double"
|
name="fas fa-check-double"
|
||||||
size="1.2em"
|
size="1.2em"
|
||||||
:color="dash_positive_color"
|
color="positive"
|
||||||
>
|
>
|
||||||
<q-tooltip>Checks passing</q-tooltip>
|
<q-tooltip>Checks passing</q-tooltip>
|
||||||
</q-icon>
|
</q-icon>
|
||||||
@@ -279,7 +279,7 @@
|
|||||||
@click="showPendingActionsModal(props.row)"
|
@click="showPendingActionsModal(props.row)"
|
||||||
name="far fa-clock"
|
name="far fa-clock"
|
||||||
size="1.4em"
|
size="1.4em"
|
||||||
:color="dash_warning_color"
|
color="warning"
|
||||||
class="cursor-pointer"
|
class="cursor-pointer"
|
||||||
>
|
>
|
||||||
<q-tooltip
|
<q-tooltip
|
||||||
@@ -303,7 +303,7 @@
|
|||||||
v-if="props.row.status === 'overdue'"
|
v-if="props.row.status === 'overdue'"
|
||||||
name="fas fa-signal"
|
name="fas fa-signal"
|
||||||
size="1.2em"
|
size="1.2em"
|
||||||
:color="dash_negative_color"
|
color="negative"
|
||||||
>
|
>
|
||||||
<q-tooltip>Agent overdue</q-tooltip>
|
<q-tooltip>Agent overdue</q-tooltip>
|
||||||
</q-icon>
|
</q-icon>
|
||||||
@@ -311,16 +311,11 @@
|
|||||||
v-else-if="props.row.status === 'offline'"
|
v-else-if="props.row.status === 'offline'"
|
||||||
name="fas fa-signal"
|
name="fas fa-signal"
|
||||||
size="1.2em"
|
size="1.2em"
|
||||||
:color="dash_warning_color"
|
color="warning"
|
||||||
>
|
>
|
||||||
<q-tooltip>Agent offline</q-tooltip>
|
<q-tooltip>Agent offline</q-tooltip>
|
||||||
</q-icon>
|
</q-icon>
|
||||||
<q-icon
|
<q-icon v-else name="fas fa-signal" size="1.2em" color="positive">
|
||||||
v-else
|
|
||||||
name="fas fa-signal"
|
|
||||||
size="1.2em"
|
|
||||||
:color="dash_positive_color"
|
|
||||||
>
|
|
||||||
<q-tooltip>Agent online</q-tooltip>
|
<q-tooltip>Agent online</q-tooltip>
|
||||||
</q-icon>
|
</q-icon>
|
||||||
</q-td>
|
</q-td>
|
||||||
@@ -378,8 +373,6 @@ export default {
|
|||||||
"local_ips",
|
"local_ips",
|
||||||
"make_model",
|
"make_model",
|
||||||
"physical_disks",
|
"physical_disks",
|
||||||
"custom_fields",
|
|
||||||
"serial_number",
|
|
||||||
];
|
];
|
||||||
// quasar filter only does visible columns so this is a hack to add hidden columns we want to filter
|
// quasar filter only does visible columns so this is a hack to add hidden columns we want to filter
|
||||||
// originally I was modifying cols directly but this led to phantom colum so doing it this way now
|
// originally I was modifying cols directly but this led to phantom colum so doing it this way now
|
||||||
@@ -439,11 +432,7 @@ export default {
|
|||||||
|
|
||||||
// Normal text filter
|
// Normal text filter
|
||||||
return allColumns.some((col) => {
|
return allColumns.some((col) => {
|
||||||
let valObj = cellValue(col, row);
|
const val = cellValue(col, row) + "";
|
||||||
if (Array.isArray(valObj)) {
|
|
||||||
valObj = valObj.map((item) => (item.value ? item.value : item));
|
|
||||||
}
|
|
||||||
const val = valObj + "";
|
|
||||||
const haystack =
|
const haystack =
|
||||||
val === "undefined" || val === "null" ? "" : val.toLowerCase();
|
val === "undefined" || val === "null" ? "" : val.toLowerCase();
|
||||||
return haystack.indexOf(search) !== -1;
|
return haystack.indexOf(search) !== -1;
|
||||||
@@ -494,9 +483,7 @@ export default {
|
|||||||
const data = {
|
const data = {
|
||||||
[db_field]: !alert_action,
|
[db_field]: !alert_action,
|
||||||
};
|
};
|
||||||
const alertColor = !alert_action
|
const alertColor = !alert_action ? "positive" : "info";
|
||||||
? this.dash_positive_color
|
|
||||||
: this.dash_info_color;
|
|
||||||
this.$axios.put(`/agents/${agent.agent_id}/`, data).then(() => {
|
this.$axios.put(`/agents/${agent.agent_id}/`, data).then(() => {
|
||||||
this.$q.notify({
|
this.$q.notify({
|
||||||
color: alertColor,
|
color: alertColor,
|
||||||
@@ -540,13 +527,7 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState([
|
...mapState(["tableHeight"]),
|
||||||
"tableHeight",
|
|
||||||
"dash_info_color",
|
|
||||||
"dash_positive_color",
|
|
||||||
"dash_negative_color",
|
|
||||||
"dash_warning_color",
|
|
||||||
]),
|
|
||||||
agentDblClickAction() {
|
agentDblClickAction() {
|
||||||
return this.$store.state.agentDblClickAction;
|
return this.$store.state.agentDblClickAction;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<q-badge v-if="alertsCount > 0" :color="badgeColor" floating transparent>{{
|
<q-badge v-if="alertsCount > 0" :color="badgeColor" floating transparent>{{
|
||||||
alertsCountText()
|
alertsCountText()
|
||||||
}}</q-badge>
|
}}</q-badge>
|
||||||
<q-menu :style="{ 'max-height': `${$q.screen.height - 100}px` }">
|
<q-menu style="max-height: 30vh">
|
||||||
<q-list separator>
|
<q-list separator>
|
||||||
<q-item v-if="alertsCount === 0">No New Alerts</q-item>
|
<q-item v-if="alertsCount === 0">No New Alerts</q-item>
|
||||||
<q-item v-for="alert in topAlerts" :key="alert.id">
|
<q-item v-for="alert in topAlerts" :key="alert.id">
|
||||||
@@ -59,7 +59,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState } from "vuex";
|
|
||||||
import mixins from "@/mixins/mixins";
|
import mixins from "@/mixins/mixins";
|
||||||
import AlertsOverview from "@/components/modals/alerts/AlertsOverview.vue";
|
import AlertsOverview from "@/components/modals/alerts/AlertsOverview.vue";
|
||||||
import { getTimeLapse } from "@/utils/format";
|
import { getTimeLapse } from "@/utils/format";
|
||||||
@@ -76,21 +75,19 @@ export default {
|
|||||||
return {
|
return {
|
||||||
alertsCount: 0,
|
alertsCount: 0,
|
||||||
topAlerts: [],
|
topAlerts: [],
|
||||||
|
errorColor: "red",
|
||||||
|
warningColor: "orange",
|
||||||
|
infoColor: "blue",
|
||||||
poll: null,
|
poll: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState([
|
|
||||||
"dash_info_color",
|
|
||||||
"dash_warning_color",
|
|
||||||
"dash_negative_color",
|
|
||||||
]),
|
|
||||||
badgeColor() {
|
badgeColor() {
|
||||||
const severities = this.topAlerts.map((alert) => alert.severity);
|
const severities = this.topAlerts.map((alert) => alert.severity);
|
||||||
|
|
||||||
if (severities.includes("error")) return this.dash_negative_color;
|
if (severities.includes("error")) return this.errorColor;
|
||||||
else if (severities.includes("warning")) return this.dash_warning_color;
|
else if (severities.includes("warning")) return this.warningColor;
|
||||||
else return this.dash_info_color;
|
else return this.infoColor;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@@ -162,9 +159,9 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
alertIconColor(severity) {
|
alertIconColor(severity) {
|
||||||
if (severity === "error") return this.dash_negative_color;
|
if (severity === "error") return this.errorColor;
|
||||||
else if (severity === "warning") return this.dash_warning_color;
|
else if (severity === "warning") return this.warningColor;
|
||||||
else return this.dash_info_color;
|
else return this.infoColor;
|
||||||
},
|
},
|
||||||
alertsCountText() {
|
alertsCountText() {
|
||||||
if (this.alertsCount > 99) return "99+";
|
if (this.alertsCount > 99) return "99+";
|
||||||
|
|||||||
@@ -98,10 +98,6 @@
|
|||||||
v-model="localRole.can_reboot_agents"
|
v-model="localRole.can_reboot_agents"
|
||||||
label="Reboot Agents"
|
label="Reboot Agents"
|
||||||
/>
|
/>
|
||||||
<q-checkbox
|
|
||||||
v-model="localRole.can_send_wol"
|
|
||||||
label="Wake-Up (WoL) Agents"
|
|
||||||
/>
|
|
||||||
<q-checkbox
|
<q-checkbox
|
||||||
v-model="localRole.can_install_agents"
|
v-model="localRole.can_install_agents"
|
||||||
label="Install Agents"
|
label="Install Agents"
|
||||||
@@ -441,8 +437,8 @@ export default {
|
|||||||
can_run_scripts: false,
|
can_run_scripts: false,
|
||||||
can_run_bulk: false,
|
can_run_bulk: false,
|
||||||
can_manage_winsvcs: false,
|
can_manage_winsvcs: false,
|
||||||
|
can_recover_agents: false,
|
||||||
can_list_agent_history: false,
|
can_list_agent_history: false,
|
||||||
can_send_wol: false,
|
|
||||||
// software perms
|
// software perms
|
||||||
can_list_software: false,
|
can_list_software: false,
|
||||||
can_manage_software: false,
|
can_manage_software: false,
|
||||||
|
|||||||
@@ -146,13 +146,6 @@
|
|||||||
<q-item-section>Run Checks</q-item-section>
|
<q-item-section>Run Checks</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
|
|
||||||
<q-item clickable v-close-popup @click="wakeUp(agent)">
|
|
||||||
<q-item-section side>
|
|
||||||
<q-icon size="xs" name="offline_bolt" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section>Wake-Up (WoL)</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
|
|
||||||
<q-item clickable>
|
<q-item clickable>
|
||||||
<q-item-section side>
|
<q-item-section side>
|
||||||
<q-icon size="xs" name="power_settings_new" />
|
<q-icon size="xs" name="power_settings_new" />
|
||||||
@@ -217,7 +210,6 @@ import {
|
|||||||
removeAgent,
|
removeAgent,
|
||||||
runRemoteBackground,
|
runRemoteBackground,
|
||||||
runTakeControl,
|
runTakeControl,
|
||||||
wakeUpWOL,
|
|
||||||
} from "@/api/agents";
|
} from "@/api/agents";
|
||||||
import { runAgentUpdateScan, runAgentUpdateInstall } from "@/api/winupdates";
|
import { runAgentUpdateScan, runAgentUpdateInstall } from "@/api/winupdates";
|
||||||
import { runAgentChecks } from "@/api/checks";
|
import { runAgentChecks } from "@/api/checks";
|
||||||
@@ -378,15 +370,6 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function wakeUp(agent) {
|
|
||||||
try {
|
|
||||||
const data = await wakeUpWOL(agent.agent_id);
|
|
||||||
notifySuccess(data);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function showRebootLaterModal(agent) {
|
function showRebootLaterModal(agent) {
|
||||||
$q.dialog({
|
$q.dialog({
|
||||||
component: RebootLater,
|
component: RebootLater,
|
||||||
@@ -515,7 +498,6 @@ export default {
|
|||||||
showPolicyAdd,
|
showPolicyAdd,
|
||||||
showAgentRecovery,
|
showAgentRecovery,
|
||||||
pingAgent,
|
pingAgent,
|
||||||
wakeUp,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -261,7 +261,7 @@
|
|||||||
<q-td v-else-if="props.row.task_result.status === 'passing'">
|
<q-td v-else-if="props.row.task_result.status === 'passing'">
|
||||||
<q-icon
|
<q-icon
|
||||||
style="font-size: 1.3rem"
|
style="font-size: 1.3rem"
|
||||||
:color="dash_positive_color"
|
color="positive"
|
||||||
name="check_circle"
|
name="check_circle"
|
||||||
>
|
>
|
||||||
<q-tooltip>Passing</q-tooltip>
|
<q-tooltip>Passing</q-tooltip>
|
||||||
@@ -271,7 +271,7 @@
|
|||||||
<q-icon
|
<q-icon
|
||||||
v-if="props.row.alert_severity === 'info'"
|
v-if="props.row.alert_severity === 'info'"
|
||||||
style="font-size: 1.3rem"
|
style="font-size: 1.3rem"
|
||||||
:color="dash_info_color"
|
color="info"
|
||||||
name="info"
|
name="info"
|
||||||
>
|
>
|
||||||
<q-tooltip>Informational</q-tooltip>
|
<q-tooltip>Informational</q-tooltip>
|
||||||
@@ -279,7 +279,7 @@
|
|||||||
<q-icon
|
<q-icon
|
||||||
v-else-if="props.row.alert_severity === 'warning'"
|
v-else-if="props.row.alert_severity === 'warning'"
|
||||||
style="font-size: 1.3rem"
|
style="font-size: 1.3rem"
|
||||||
:color="dash_warning_color"
|
color="warning"
|
||||||
name="warning"
|
name="warning"
|
||||||
>
|
>
|
||||||
<q-tooltip>Warning</q-tooltip>
|
<q-tooltip>Warning</q-tooltip>
|
||||||
@@ -287,7 +287,7 @@
|
|||||||
<q-icon
|
<q-icon
|
||||||
v-else
|
v-else
|
||||||
style="font-size: 1.3rem"
|
style="font-size: 1.3rem"
|
||||||
:color="dash_negative_color"
|
color="negative"
|
||||||
name="error"
|
name="error"
|
||||||
>
|
>
|
||||||
<q-tooltip>Error</q-tooltip>
|
<q-tooltip>Error</q-tooltip>
|
||||||
@@ -418,10 +418,6 @@ export default {
|
|||||||
const tabHeight = computed(() => store.state.tabHeight);
|
const tabHeight = computed(() => store.state.tabHeight);
|
||||||
const agentPlatform = computed(() => store.state.agentPlatform);
|
const agentPlatform = computed(() => store.state.agentPlatform);
|
||||||
const formatDate = computed(() => store.getters.formatDate);
|
const formatDate = computed(() => store.getters.formatDate);
|
||||||
const dash_info_color = computed(() => store.state.dash_info_color);
|
|
||||||
const dash_positive_color = computed(() => store.state.dash_positive_color);
|
|
||||||
const dash_negative_color = computed(() => store.state.dash_negative_color);
|
|
||||||
const dash_warning_color = computed(() => store.state.dash_warning_color);
|
|
||||||
|
|
||||||
// setup quasar
|
// setup quasar
|
||||||
const $q = useQuasar();
|
const $q = useQuasar();
|
||||||
@@ -556,10 +552,6 @@ export default {
|
|||||||
selectedAgent,
|
selectedAgent,
|
||||||
tabHeight,
|
tabHeight,
|
||||||
agentPlatform,
|
agentPlatform,
|
||||||
dash_info_color,
|
|
||||||
dash_positive_color,
|
|
||||||
dash_warning_color,
|
|
||||||
dash_negative_color,
|
|
||||||
|
|
||||||
// non-reactive data
|
// non-reactive data
|
||||||
columns,
|
columns,
|
||||||
|
|||||||
@@ -301,7 +301,7 @@
|
|||||||
<q-td v-else-if="props.row.check_result.status === 'passing'">
|
<q-td v-else-if="props.row.check_result.status === 'passing'">
|
||||||
<q-icon
|
<q-icon
|
||||||
style="font-size: 1.3rem"
|
style="font-size: 1.3rem"
|
||||||
:color="dash_positive_color"
|
color="positive"
|
||||||
name="check_circle"
|
name="check_circle"
|
||||||
>
|
>
|
||||||
<q-tooltip>Passing</q-tooltip>
|
<q-tooltip>Passing</q-tooltip>
|
||||||
@@ -311,7 +311,7 @@
|
|||||||
<q-icon
|
<q-icon
|
||||||
v-if="getAlertSeverity(props.row) === 'info'"
|
v-if="getAlertSeverity(props.row) === 'info'"
|
||||||
style="font-size: 1.3rem"
|
style="font-size: 1.3rem"
|
||||||
:color="dash_info_color"
|
color="info"
|
||||||
name="info"
|
name="info"
|
||||||
>
|
>
|
||||||
<q-tooltip>Informational</q-tooltip>
|
<q-tooltip>Informational</q-tooltip>
|
||||||
@@ -319,7 +319,7 @@
|
|||||||
<q-icon
|
<q-icon
|
||||||
v-else-if="getAlertSeverity(props.row) === 'warning'"
|
v-else-if="getAlertSeverity(props.row) === 'warning'"
|
||||||
style="font-size: 1.3rem"
|
style="font-size: 1.3rem"
|
||||||
:color="dash_warning_color"
|
color="warning"
|
||||||
name="warning"
|
name="warning"
|
||||||
>
|
>
|
||||||
<q-tooltip>Warning</q-tooltip>
|
<q-tooltip>Warning</q-tooltip>
|
||||||
@@ -327,7 +327,7 @@
|
|||||||
<q-icon
|
<q-icon
|
||||||
v-else
|
v-else
|
||||||
style="font-size: 1.3rem"
|
style="font-size: 1.3rem"
|
||||||
:color="dash_negative_color"
|
color="negative"
|
||||||
name="error"
|
name="error"
|
||||||
>
|
>
|
||||||
<q-tooltip>Error</q-tooltip>
|
<q-tooltip>Error</q-tooltip>
|
||||||
@@ -479,10 +479,6 @@ export default {
|
|||||||
const tabHeight = computed(() => store.state.tabHeight);
|
const tabHeight = computed(() => store.state.tabHeight);
|
||||||
const agentPlatform = computed(() => store.state.agentPlatform);
|
const agentPlatform = computed(() => store.state.agentPlatform);
|
||||||
const formatDate = computed(() => store.getters.formatDate);
|
const formatDate = computed(() => store.getters.formatDate);
|
||||||
const dash_info_color = computed(() => store.state.dash_info_color);
|
|
||||||
const dash_positive_color = computed(() => store.state.dash_positive_color);
|
|
||||||
const dash_negative_color = computed(() => store.state.dash_negative_color);
|
|
||||||
const dash_warning_color = computed(() => store.state.dash_warning_color);
|
|
||||||
|
|
||||||
// setup quasar
|
// setup quasar
|
||||||
const $q = useQuasar();
|
const $q = useQuasar();
|
||||||
@@ -657,10 +653,6 @@ export default {
|
|||||||
tabHeight,
|
tabHeight,
|
||||||
selectedAgent,
|
selectedAgent,
|
||||||
agentPlatform,
|
agentPlatform,
|
||||||
dash_info_color,
|
|
||||||
dash_positive_color,
|
|
||||||
dash_warning_color,
|
|
||||||
dash_negative_color,
|
|
||||||
|
|
||||||
// non-reactive data
|
// non-reactive data
|
||||||
columns,
|
columns,
|
||||||
|
|||||||
@@ -18,33 +18,6 @@
|
|||||||
icon="refresh"
|
icon="refresh"
|
||||||
@click="refreshSummary"
|
@click="refreshSummary"
|
||||||
/>
|
/>
|
||||||
<q-icon
|
|
||||||
v-if="summary.status === 'overdue'"
|
|
||||||
name="fas fa-signal"
|
|
||||||
size="1.2em"
|
|
||||||
:color="dash_negative_color"
|
|
||||||
class="q-mr-sm"
|
|
||||||
>
|
|
||||||
<q-tooltip>Agent overdue</q-tooltip>
|
|
||||||
</q-icon>
|
|
||||||
<q-icon
|
|
||||||
v-else-if="summary.status === 'offline'"
|
|
||||||
name="fas fa-signal"
|
|
||||||
size="1.2em"
|
|
||||||
:color="dash_warning_color"
|
|
||||||
class="q-mr-sm"
|
|
||||||
>
|
|
||||||
<q-tooltip>Agent offline</q-tooltip>
|
|
||||||
</q-icon>
|
|
||||||
<q-icon
|
|
||||||
v-else
|
|
||||||
name="fas fa-signal"
|
|
||||||
size="1.2em"
|
|
||||||
:color="dash_positive_color"
|
|
||||||
class="q-mr-sm"
|
|
||||||
>
|
|
||||||
<q-tooltip>Agent online</q-tooltip>
|
|
||||||
</q-icon>
|
|
||||||
<b>{{ summary.hostname }}</b>
|
<b>{{ summary.hostname }}</b>
|
||||||
<span v-if="summary.maintenance_mode">
|
<span v-if="summary.maintenance_mode">
|
||||||
• <q-badge color="green"> Maintenance Mode </q-badge>
|
• <q-badge color="green"> Maintenance Mode </q-badge>
|
||||||
@@ -87,7 +60,7 @@
|
|||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section>{{ summary.make_model }}</q-item-section>
|
<q-item-section>{{ summary.make_model }}</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<q-item>
|
<q-item v-for="(cpu, i) in summary.cpu_model" :key="cpu + i">
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
<q-icon name="fas fa-microchip" />
|
<q-icon name="fas fa-microchip" />
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
@@ -114,13 +87,6 @@
|
|||||||
</q-item-section>
|
</q-item-section>
|
||||||
<q-item-section>{{ summary.graphics }}</q-item-section>
|
<q-item-section>{{ summary.graphics }}</q-item-section>
|
||||||
</q-item>
|
</q-item>
|
||||||
<!-- serial -->
|
|
||||||
<q-item v-if="serial_number">
|
|
||||||
<q-item-section avatar>
|
|
||||||
<q-icon name="fa-solid fa-barcode" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section>{{ serial_number }}</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
<q-item>
|
<q-item>
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
<q-icon name="fas fa-globe-americas" />
|
<q-icon name="fas fa-globe-americas" />
|
||||||
@@ -144,7 +110,7 @@
|
|||||||
size="lg"
|
size="lg"
|
||||||
square
|
square
|
||||||
icon="done"
|
icon="done"
|
||||||
:color="dash_positive_color"
|
color="green"
|
||||||
text-color="white"
|
text-color="white"
|
||||||
/>
|
/>
|
||||||
<small>{{ summary.checks.passing }} checks passing</small>
|
<small>{{ summary.checks.passing }} checks passing</small>
|
||||||
@@ -154,7 +120,7 @@
|
|||||||
size="lg"
|
size="lg"
|
||||||
square
|
square
|
||||||
icon="cancel"
|
icon="cancel"
|
||||||
:color="dash_negative_color"
|
color="red"
|
||||||
text-color="white"
|
text-color="white"
|
||||||
/>
|
/>
|
||||||
<small>{{ summary.checks.failing }} checks failing</small>
|
<small>{{ summary.checks.failing }} checks failing</small>
|
||||||
@@ -164,7 +130,7 @@
|
|||||||
size="lg"
|
size="lg"
|
||||||
square
|
square
|
||||||
icon="warning"
|
icon="warning"
|
||||||
:color="dash_warning_color"
|
color="warning"
|
||||||
text-color="white"
|
text-color="white"
|
||||||
/>
|
/>
|
||||||
<small>{{ summary.checks.warning }} checks warning</small>
|
<small>{{ summary.checks.warning }} checks warning</small>
|
||||||
@@ -174,7 +140,7 @@
|
|||||||
size="lg"
|
size="lg"
|
||||||
square
|
square
|
||||||
icon="info"
|
icon="info"
|
||||||
:color="dash_info_color"
|
color="info"
|
||||||
text-color="white"
|
text-color="white"
|
||||||
/>
|
/>
|
||||||
<small>{{ summary.checks.info }} checks info</small>
|
<small>{{ summary.checks.info }} checks info</small>
|
||||||
@@ -192,20 +158,6 @@
|
|||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>No checks</div>
|
<div v-else>No checks</div>
|
||||||
|
|
||||||
<span
|
|
||||||
v-if="customFields.length > 0"
|
|
||||||
class="text-subtitle2 text-bold block q-mt-xl"
|
|
||||||
>Custom Fields</span
|
|
||||||
>
|
|
||||||
<q-list dense>
|
|
||||||
<q-item v-for="(field, i) in customFields" :key="field + i">
|
|
||||||
<q-item-section thumbnail>
|
|
||||||
<q-icon name="fas fa-user" size="xs" />
|
|
||||||
</q-item-section>
|
|
||||||
<q-item-section>{{ field.name }}: {{ field.value }}</q-item-section>
|
|
||||||
</q-item>
|
|
||||||
</q-list>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-1"></div>
|
<div class="col-1"></div>
|
||||||
<!-- right -->
|
<!-- right -->
|
||||||
@@ -241,7 +193,6 @@ import {
|
|||||||
openAgentWindow,
|
openAgentWindow,
|
||||||
} from "@/api/agents";
|
} from "@/api/agents";
|
||||||
import { notifySuccess } from "@/utils/notify";
|
import { notifySuccess } from "@/utils/notify";
|
||||||
import { fetchCustomFields } from "@/api/core";
|
|
||||||
|
|
||||||
// ui imports
|
// ui imports
|
||||||
import AgentActionMenu from "@/components/agents/AgentActionMenu.vue";
|
import AgentActionMenu from "@/components/agents/AgentActionMenu.vue";
|
||||||
@@ -256,34 +207,18 @@ export default {
|
|||||||
const store = useStore();
|
const store = useStore();
|
||||||
const selectedAgent = computed(() => store.state.selectedRow);
|
const selectedAgent = computed(() => store.state.selectedRow);
|
||||||
const refreshSummaryTab = computed(() => store.state.refreshSummaryTab);
|
const refreshSummaryTab = computed(() => store.state.refreshSummaryTab);
|
||||||
const dash_info_color = computed(() => store.state.dash_info_color);
|
|
||||||
const dash_positive_color = computed(() => store.state.dash_positive_color);
|
|
||||||
const dash_negative_color = computed(() => store.state.dash_negative_color);
|
|
||||||
const dash_warning_color = computed(() => store.state.dash_warning_color);
|
|
||||||
|
|
||||||
// summary tab logic
|
// summary tab logic
|
||||||
const summary = ref(null);
|
const summary = ref(null);
|
||||||
const customFieldsDefinitions = ref(null);
|
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|
||||||
const serial_number = computed(() => {
|
|
||||||
return summary.value.wmi_detail.bios?.[0]?.[0]?.SerialNumber;
|
|
||||||
});
|
|
||||||
|
|
||||||
const cpu = computed(() => {
|
|
||||||
if (summary.value.cpu_model?.length > 1) {
|
|
||||||
return `${summary.value.cpu_model.length}x ${summary.value.cpu_model[0]}`;
|
|
||||||
}
|
|
||||||
return summary.value.cpu_model[0];
|
|
||||||
});
|
|
||||||
|
|
||||||
function diskBarColor(percent) {
|
function diskBarColor(percent) {
|
||||||
if (percent < 80) {
|
if (percent < 80) {
|
||||||
return dash_positive_color.value;
|
return "positive";
|
||||||
} else if (percent > 80 && percent < 95) {
|
} else if (percent > 80 && percent < 95) {
|
||||||
return dash_warning_color.value;
|
return "warning";
|
||||||
} else {
|
} else {
|
||||||
return dash_negative_color.value;
|
return "negative";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,37 +236,9 @@ export default {
|
|||||||
return ret;
|
return ret;
|
||||||
});
|
});
|
||||||
|
|
||||||
const customFields = computed(() => {
|
|
||||||
if (!summary.value.custom_fields) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
if (!customFieldsDefinitions.value) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
const ret = [];
|
|
||||||
for (const customField of summary.value.custom_fields) {
|
|
||||||
const definition = customFieldsDefinitions.value.find(
|
|
||||||
(def) => def.id === customField.field
|
|
||||||
);
|
|
||||||
if (
|
|
||||||
definition &&
|
|
||||||
!definition.hide_in_ui &&
|
|
||||||
customField.value?.length > 0
|
|
||||||
) {
|
|
||||||
ret.push({
|
|
||||||
name: definition.name,
|
|
||||||
value: customField.value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
});
|
|
||||||
|
|
||||||
async function getSummary() {
|
async function getSummary() {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
summary.value = await fetchAgent(selectedAgent.value);
|
summary.value = await fetchAgent(selectedAgent.value);
|
||||||
customFieldsDefinitions.value = await fetchCustomFields();
|
|
||||||
store.commit("setRefreshSummaryTab", false);
|
store.commit("setRefreshSummaryTab", false);
|
||||||
store.commit("setAgentPlatform", summary.value.plat);
|
store.commit("setAgentPlatform", summary.value.plat);
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
@@ -339,7 +246,6 @@ export default {
|
|||||||
|
|
||||||
async function refreshSummary() {
|
async function refreshSummary() {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
summary.value = await fetchAgent(selectedAgent.value);
|
|
||||||
try {
|
try {
|
||||||
const result = await refreshAgentWMI(selectedAgent.value);
|
const result = await refreshAgentWMI(selectedAgent.value);
|
||||||
await getSummary();
|
await getSummary();
|
||||||
@@ -371,16 +277,9 @@ export default {
|
|||||||
return {
|
return {
|
||||||
// reactive data
|
// reactive data
|
||||||
summary,
|
summary,
|
||||||
customFields,
|
|
||||||
loading,
|
loading,
|
||||||
selectedAgent,
|
selectedAgent,
|
||||||
disks,
|
disks,
|
||||||
dash_info_color,
|
|
||||||
dash_positive_color,
|
|
||||||
dash_warning_color,
|
|
||||||
dash_negative_color,
|
|
||||||
serial_number,
|
|
||||||
cpu,
|
|
||||||
|
|
||||||
// methods
|
// methods
|
||||||
getSummary,
|
getSummary,
|
||||||
|
|||||||
@@ -128,7 +128,7 @@
|
|||||||
<q-icon
|
<q-icon
|
||||||
v-else-if="props.row.action === 'ignore'"
|
v-else-if="props.row.action === 'ignore'"
|
||||||
name="fas fa-check"
|
name="fas fa-check"
|
||||||
:color="dash_negative_color"
|
color="negative"
|
||||||
>
|
>
|
||||||
<q-tooltip>Ignore</q-tooltip>
|
<q-tooltip>Ignore</q-tooltip>
|
||||||
</q-icon>
|
</q-icon>
|
||||||
@@ -144,7 +144,7 @@
|
|||||||
<q-icon
|
<q-icon
|
||||||
v-if="props.row.installed"
|
v-if="props.row.installed"
|
||||||
name="fas fa-check"
|
name="fas fa-check"
|
||||||
:color="dash_positive_color"
|
color="positive"
|
||||||
>
|
>
|
||||||
<q-tooltip>Installed</q-tooltip>
|
<q-tooltip>Installed</q-tooltip>
|
||||||
</q-icon>
|
</q-icon>
|
||||||
@@ -158,15 +158,11 @@
|
|||||||
<q-icon
|
<q-icon
|
||||||
v-else-if="props.row.action == 'ignore'"
|
v-else-if="props.row.action == 'ignore'"
|
||||||
name="fas fa-ban"
|
name="fas fa-ban"
|
||||||
:color="dash_negative_color"
|
color="negative"
|
||||||
>
|
>
|
||||||
<q-tooltip>Ignored</q-tooltip>
|
<q-tooltip>Ignored</q-tooltip>
|
||||||
</q-icon>
|
</q-icon>
|
||||||
<q-icon
|
<q-icon v-else name="fas fa-exclamation" color="warning">
|
||||||
v-else
|
|
||||||
name="fas fa-exclamation"
|
|
||||||
:color="dash_warning_color"
|
|
||||||
>
|
|
||||||
<q-tooltip>Missing</q-tooltip>
|
<q-tooltip>Missing</q-tooltip>
|
||||||
</q-icon>
|
</q-icon>
|
||||||
</q-td>
|
</q-td>
|
||||||
@@ -255,9 +251,6 @@ export default {
|
|||||||
const tabHeight = computed(() => store.state.tabHeight);
|
const tabHeight = computed(() => store.state.tabHeight);
|
||||||
const agentPlatform = computed(() => store.state.agentPlatform);
|
const agentPlatform = computed(() => store.state.agentPlatform);
|
||||||
const formatDate = computed(() => store.getters.formatDate);
|
const formatDate = computed(() => store.getters.formatDate);
|
||||||
const dash_positive_color = computed(() => store.state.dash_positive_color);
|
|
||||||
const dash_negative_color = computed(() => store.state.dash_negative_color);
|
|
||||||
const dash_warning_color = computed(() => store.state.dash_warning_color);
|
|
||||||
|
|
||||||
// setup quasar
|
// setup quasar
|
||||||
const $q = useQuasar();
|
const $q = useQuasar();
|
||||||
@@ -355,9 +348,6 @@ export default {
|
|||||||
selectedAgent,
|
selectedAgent,
|
||||||
tabHeight,
|
tabHeight,
|
||||||
agentPlatform,
|
agentPlatform,
|
||||||
dash_positive_color,
|
|
||||||
dash_warning_color,
|
|
||||||
dash_negative_color,
|
|
||||||
|
|
||||||
// non-reactive data
|
// non-reactive data
|
||||||
columns,
|
columns,
|
||||||
|
|||||||
@@ -217,7 +217,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState } from "vuex";
|
|
||||||
import mixins from "@/mixins/mixins";
|
import mixins from "@/mixins/mixins";
|
||||||
import PolicyStatus from "@/components/automation/modals/PolicyStatus.vue";
|
import PolicyStatus from "@/components/automation/modals/PolicyStatus.vue";
|
||||||
import DiskSpaceCheck from "@/components/checks/DiskSpaceCheck.vue";
|
import DiskSpaceCheck from "@/components/checks/DiskSpaceCheck.vue";
|
||||||
@@ -269,9 +268,6 @@ export default {
|
|||||||
if (newValue !== oldValue) this.getChecks();
|
if (newValue !== oldValue) this.getChecks();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
...mapState(["dash_positive_color", "dash_warning_color"]),
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
getChecks() {
|
getChecks() {
|
||||||
this.$q.loading.show();
|
this.$q.loading.show();
|
||||||
@@ -299,9 +295,7 @@ export default {
|
|||||||
|
|
||||||
data.check_alert = true;
|
data.check_alert = true;
|
||||||
const act = !action ? "enabled" : "disabled";
|
const act = !action ? "enabled" : "disabled";
|
||||||
const color = !action
|
const color = !action ? "positive" : "warning";
|
||||||
? this.dash_positive_color
|
|
||||||
: this.dash_warning_color;
|
|
||||||
this.$axios
|
this.$axios
|
||||||
.put(`/checks/${id}/`, data)
|
.put(`/checks/${id}/`, data)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
<q-td v-if="props.row.status === 'passing'">
|
<q-td v-if="props.row.status === 'passing'">
|
||||||
<q-icon
|
<q-icon
|
||||||
style="font-size: 1.3rem"
|
style="font-size: 1.3rem"
|
||||||
:color="dash_positive_color"
|
color="positive"
|
||||||
name="check_circle"
|
name="check_circle"
|
||||||
>
|
>
|
||||||
<q-tooltip>Passing</q-tooltip>
|
<q-tooltip>Passing</q-tooltip>
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
<q-icon
|
<q-icon
|
||||||
v-if="props.row.alert_severity === 'info'"
|
v-if="props.row.alert_severity === 'info'"
|
||||||
style="font-size: 1.3rem"
|
style="font-size: 1.3rem"
|
||||||
:color="dash_info_color"
|
color="info"
|
||||||
name="info"
|
name="info"
|
||||||
>
|
>
|
||||||
<q-tooltip>Informational</q-tooltip>
|
<q-tooltip>Informational</q-tooltip>
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
<q-icon
|
<q-icon
|
||||||
v-else-if="props.row.alert_severity === 'warning'"
|
v-else-if="props.row.alert_severity === 'warning'"
|
||||||
style="font-size: 1.3rem"
|
style="font-size: 1.3rem"
|
||||||
:color="dash_warning_color"
|
color="warning"
|
||||||
name="warning"
|
name="warning"
|
||||||
>
|
>
|
||||||
<q-tooltip>Warning</q-tooltip>
|
<q-tooltip>Warning</q-tooltip>
|
||||||
@@ -67,7 +67,7 @@
|
|||||||
<q-icon
|
<q-icon
|
||||||
v-else
|
v-else
|
||||||
style="font-size: 1.3rem"
|
style="font-size: 1.3rem"
|
||||||
:color="dash_negative_color"
|
color="negative"
|
||||||
name="error"
|
name="error"
|
||||||
>
|
>
|
||||||
<q-tooltip>Error</q-tooltip>
|
<q-tooltip>Error</q-tooltip>
|
||||||
@@ -148,7 +148,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
import { useStore, mapState } from "vuex";
|
import { useStore } from "vuex";
|
||||||
import ScriptOutput from "@/components/checks/ScriptOutput.vue";
|
import ScriptOutput from "@/components/checks/ScriptOutput.vue";
|
||||||
import EventLogCheckOutput from "@/components/checks/EventLogCheckOutput.vue";
|
import EventLogCheckOutput from "@/components/checks/EventLogCheckOutput.vue";
|
||||||
|
|
||||||
@@ -220,12 +220,6 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapState([
|
|
||||||
"dash_info_color",
|
|
||||||
"dash_positive_color",
|
|
||||||
"dash_negative_color",
|
|
||||||
"dash_warning_color",
|
|
||||||
]),
|
|
||||||
title() {
|
title() {
|
||||||
return !!this.item.readable_desc
|
return !!this.item.readable_desc
|
||||||
? this.item.readable_desc + " Status"
|
? this.item.readable_desc + " Status"
|
||||||
|
|||||||
@@ -304,9 +304,6 @@ export default {
|
|||||||
// setup vuex
|
// setup vuex
|
||||||
const store = useStore();
|
const store = useStore();
|
||||||
const formatDate = computed(() => store.getters.formatDate);
|
const formatDate = computed(() => store.getters.formatDate);
|
||||||
const dash_positive_color = computed(() => store.state.dash_positive_color);
|
|
||||||
const dash_negative_color = computed(() => store.state.dash_negative_color);
|
|
||||||
const dash_warning_color = computed(() => store.state.dash_warning_color);
|
|
||||||
|
|
||||||
// setup dropdowns
|
// setup dropdowns
|
||||||
const { clientOptions, getClientOptions } = useClientDropdown();
|
const { clientOptions, getClientOptions } = useClientDropdown();
|
||||||
@@ -384,18 +381,12 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function formatActionColor(action) {
|
function formatActionColor(action) {
|
||||||
switch (action.toLowerCase()) {
|
if (action === "add") return "success";
|
||||||
case "modify":
|
else if (action === "agent_install") return "success";
|
||||||
return dash_warning_color.value;
|
else if (action === "modify") return "warning";
|
||||||
case "add":
|
else if (action === "delete") return "negative";
|
||||||
case "agent_install":
|
else if (action === "failed_login") return "negative";
|
||||||
return dash_positive_color.value;
|
else return "primary";
|
||||||
case "delete":
|
|
||||||
case "failed_login":
|
|
||||||
return dash_negative_color.value;
|
|
||||||
default:
|
|
||||||
return "primary";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// watchers
|
// watchers
|
||||||
|
|||||||
@@ -68,25 +68,25 @@
|
|||||||
/>
|
/>
|
||||||
<q-radio
|
<q-radio
|
||||||
v-model="logLevelFilter"
|
v-model="logLevelFilter"
|
||||||
:color="dash_info_color"
|
color="cyan"
|
||||||
val="info"
|
val="info"
|
||||||
label="Info"
|
label="Info"
|
||||||
/>
|
/>
|
||||||
<q-radio
|
<q-radio
|
||||||
v-model="logLevelFilter"
|
v-model="logLevelFilter"
|
||||||
:color="dash_negative_color"
|
color="red"
|
||||||
val="critical"
|
val="critical"
|
||||||
label="Critical"
|
label="Critical"
|
||||||
/>
|
/>
|
||||||
<q-radio
|
<q-radio
|
||||||
v-model="logLevelFilter"
|
v-model="logLevelFilter"
|
||||||
:color="dash_negative_color"
|
color="red"
|
||||||
val="error"
|
val="error"
|
||||||
label="Error"
|
label="Error"
|
||||||
/>
|
/>
|
||||||
<q-radio
|
<q-radio
|
||||||
v-model="logLevelFilter"
|
v-model="logLevelFilter"
|
||||||
:color="dash_warning_color"
|
color="yellow"
|
||||||
val="warning"
|
val="warning"
|
||||||
label="Warning"
|
label="Warning"
|
||||||
/>
|
/>
|
||||||
@@ -109,7 +109,7 @@
|
|||||||
<template v-slot:top-row>
|
<template v-slot:top-row>
|
||||||
<q-tr v-if="Array.isArray(debugLog) && debugLog.length === 1000">
|
<q-tr v-if="Array.isArray(debugLog) && debugLog.length === 1000">
|
||||||
<q-td colspan="100%">
|
<q-td colspan="100%">
|
||||||
<q-icon name="warning" :color="dash_warning_color" />
|
<q-icon name="warning" color="warning" />
|
||||||
Results are limited to 1000 rows.
|
Results are limited to 1000 rows.
|
||||||
</q-td>
|
</q-td>
|
||||||
</q-tr>
|
</q-tr>
|
||||||
@@ -203,10 +203,6 @@ export default {
|
|||||||
const store = useStore();
|
const store = useStore();
|
||||||
|
|
||||||
const formatDate = computed(() => store.getters.formatDate);
|
const formatDate = computed(() => store.getters.formatDate);
|
||||||
const dash_info_color = computed(() => store.state.dash_info_color);
|
|
||||||
const dash_positive_color = computed(() => store.state.dash_positive_color);
|
|
||||||
const dash_negative_color = computed(() => store.state.dash_negative_color);
|
|
||||||
const dash_warning_color = computed(() => store.state.dash_warning_color);
|
|
||||||
|
|
||||||
// setup dropdowns
|
// setup dropdowns
|
||||||
const { agentOptions, getAgentOptions } = useAgentDropdown();
|
const { agentOptions, getAgentOptions } = useAgentDropdown();
|
||||||
@@ -265,10 +261,6 @@ export default {
|
|||||||
agentOptions,
|
agentOptions,
|
||||||
loading,
|
loading,
|
||||||
filter,
|
filter,
|
||||||
dash_info_color,
|
|
||||||
dash_positive_color,
|
|
||||||
dash_warning_color,
|
|
||||||
dash_negative_color,
|
|
||||||
|
|
||||||
// non-reactive data
|
// non-reactive data
|
||||||
columns,
|
columns,
|
||||||
|
|||||||
@@ -94,7 +94,7 @@
|
|||||||
class="q-pr-sm"
|
class="q-pr-sm"
|
||||||
name="fas fa-signal"
|
name="fas fa-signal"
|
||||||
size="1.2em"
|
size="1.2em"
|
||||||
:color="dash_warning_color"
|
color="warning"
|
||||||
/>
|
/>
|
||||||
Mark an agent as
|
Mark an agent as
|
||||||
<span class="text-weight-bold">offline</span> if it has
|
<span class="text-weight-bold">offline</span> if it has
|
||||||
@@ -120,7 +120,7 @@
|
|||||||
class="q-pr-sm"
|
class="q-pr-sm"
|
||||||
name="fas fa-signal"
|
name="fas fa-signal"
|
||||||
size="1.2em"
|
size="1.2em"
|
||||||
:color="dash_negative_color"
|
color="negative"
|
||||||
/>
|
/>
|
||||||
Mark an agent as
|
Mark an agent as
|
||||||
<span class="text-weight-bold">overdue</span> if it has
|
<span class="text-weight-bold">overdue</span> if it has
|
||||||
@@ -373,7 +373,6 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapState } from "vuex";
|
|
||||||
import { useDialogPluginComponent } from "quasar";
|
import { useDialogPluginComponent } from "quasar";
|
||||||
import mixins from "@/mixins/mixins";
|
import mixins from "@/mixins/mixins";
|
||||||
import PatchPolicyForm from "@/components/modals/agents/PatchPolicyForm.vue";
|
import PatchPolicyForm from "@/components/modals/agents/PatchPolicyForm.vue";
|
||||||
@@ -550,9 +549,6 @@ export default {
|
|||||||
return result.trimEnd(",");
|
return result.trimEnd(",");
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
...mapState(["dash_warning_color", "dash_negative_color"]),
|
|
||||||
},
|
|
||||||
mounted() {
|
mounted() {
|
||||||
// Get custom fields
|
// Get custom fields
|
||||||
this.getCustomFields("agent").then((r) => {
|
this.getCustomFields("agent").then((r) => {
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
<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>
|
||||||
@@ -509,49 +508,6 @@
|
|||||||
<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">
|
||||||
|
|||||||
@@ -82,98 +82,6 @@
|
|||||||
class="col-4"
|
class="col-4"
|
||||||
/>
|
/>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-card-section class="row">
|
|
||||||
<div class="col-2">Dashboard Info Color:</div>
|
|
||||||
<div class="col-2"></div>
|
|
||||||
<q-input
|
|
||||||
outlined
|
|
||||||
dense
|
|
||||||
v-model="dash_info_color"
|
|
||||||
class="col-8"
|
|
||||||
>
|
|
||||||
<template v-slot:after>
|
|
||||||
<q-btn
|
|
||||||
round
|
|
||||||
dense
|
|
||||||
flat
|
|
||||||
size="sm"
|
|
||||||
icon="info"
|
|
||||||
@click="openURL(quasar_color_url)"
|
|
||||||
>
|
|
||||||
<q-tooltip>Click to see color options</q-tooltip>
|
|
||||||
</q-btn>
|
|
||||||
</template>
|
|
||||||
</q-input>
|
|
||||||
</q-card-section>
|
|
||||||
<q-card-section class="row">
|
|
||||||
<div class="col-2">Dashboard Positive Color:</div>
|
|
||||||
<div class="col-2"></div>
|
|
||||||
<q-input
|
|
||||||
outlined
|
|
||||||
dense
|
|
||||||
v-model="dash_positive_color"
|
|
||||||
class="col-8"
|
|
||||||
>
|
|
||||||
<template v-slot:after>
|
|
||||||
<q-btn
|
|
||||||
round
|
|
||||||
dense
|
|
||||||
flat
|
|
||||||
size="sm"
|
|
||||||
icon="info"
|
|
||||||
@click="openURL(quasar_color_url)"
|
|
||||||
>
|
|
||||||
<q-tooltip>Click to see color options</q-tooltip>
|
|
||||||
</q-btn>
|
|
||||||
</template>
|
|
||||||
</q-input>
|
|
||||||
</q-card-section>
|
|
||||||
<q-card-section class="row">
|
|
||||||
<div class="col-2">Dashboard Negative Color:</div>
|
|
||||||
<div class="col-2"></div>
|
|
||||||
<q-input
|
|
||||||
outlined
|
|
||||||
dense
|
|
||||||
v-model="dash_negative_color"
|
|
||||||
class="col-8"
|
|
||||||
>
|
|
||||||
<template v-slot:after>
|
|
||||||
<q-btn
|
|
||||||
round
|
|
||||||
dense
|
|
||||||
flat
|
|
||||||
size="sm"
|
|
||||||
icon="info"
|
|
||||||
@click="openURL(quasar_color_url)"
|
|
||||||
>
|
|
||||||
<q-tooltip>Click to see color options</q-tooltip>
|
|
||||||
</q-btn>
|
|
||||||
</template>
|
|
||||||
</q-input>
|
|
||||||
</q-card-section>
|
|
||||||
<q-card-section class="row">
|
|
||||||
<div class="col-2">Dashboard Warning Color:</div>
|
|
||||||
<div class="col-2"></div>
|
|
||||||
<q-input
|
|
||||||
outlined
|
|
||||||
dense
|
|
||||||
v-model="dash_warning_color"
|
|
||||||
class="col-8"
|
|
||||||
>
|
|
||||||
<template v-slot:after>
|
|
||||||
<q-btn
|
|
||||||
round
|
|
||||||
dense
|
|
||||||
flat
|
|
||||||
size="sm"
|
|
||||||
icon="info"
|
|
||||||
@click="openURL(quasar_color_url)"
|
|
||||||
>
|
|
||||||
<q-tooltip>Click to see color options</q-tooltip>
|
|
||||||
</q-btn>
|
|
||||||
</template>
|
|
||||||
</q-input>
|
|
||||||
</q-card-section>
|
|
||||||
<q-card-section class="row">
|
<q-card-section class="row">
|
||||||
<div class="col-2">Client Sort:</div>
|
<div class="col-2">Client Sort:</div>
|
||||||
<div class="col-2"></div>
|
<div class="col-2"></div>
|
||||||
@@ -248,14 +156,9 @@ export default {
|
|||||||
tab: "ui",
|
tab: "ui",
|
||||||
splitterModel: 20,
|
splitterModel: 20,
|
||||||
loading_bar_color: "",
|
loading_bar_color: "",
|
||||||
dash_info_color: "",
|
|
||||||
dash_positive_color: "",
|
|
||||||
dash_negative_color: "",
|
|
||||||
dash_warning_color: "",
|
|
||||||
urlActions: [],
|
urlActions: [],
|
||||||
clear_search_when_switching: true,
|
clear_search_when_switching: true,
|
||||||
date_format: "",
|
date_format: "",
|
||||||
quasar_color_url: "https://quasar.dev/style/color-palette",
|
|
||||||
clientTreeSortOptions: [
|
clientTreeSortOptions: [
|
||||||
{
|
{
|
||||||
label: "Sort alphabetically, moving failing clients to the top",
|
label: "Sort alphabetically, moving failing clients to the top",
|
||||||
@@ -332,10 +235,6 @@ export default {
|
|||||||
this.defaultAgentTblTab = r.data.default_agent_tbl_tab;
|
this.defaultAgentTblTab = r.data.default_agent_tbl_tab;
|
||||||
this.clientTreeSort = r.data.client_tree_sort;
|
this.clientTreeSort = r.data.client_tree_sort;
|
||||||
this.loading_bar_color = r.data.loading_bar_color;
|
this.loading_bar_color = r.data.loading_bar_color;
|
||||||
this.dash_info_color = r.data.dash_info_color;
|
|
||||||
this.dash_positive_color = r.data.dash_positive_color;
|
|
||||||
this.dash_negative_color = r.data.dash_negative_color;
|
|
||||||
this.dash_warning_color = r.data.dash_warning_color;
|
|
||||||
this.clear_search_when_switching = r.data.clear_search_when_switching;
|
this.clear_search_when_switching = r.data.clear_search_when_switching;
|
||||||
this.date_format = r.data.date_format;
|
this.date_format = r.data.date_format;
|
||||||
});
|
});
|
||||||
@@ -354,10 +253,6 @@ export default {
|
|||||||
default_agent_tbl_tab: this.defaultAgentTblTab,
|
default_agent_tbl_tab: this.defaultAgentTblTab,
|
||||||
client_tree_sort: this.clientTreeSort,
|
client_tree_sort: this.clientTreeSort,
|
||||||
loading_bar_color: this.loading_bar_color,
|
loading_bar_color: this.loading_bar_color,
|
||||||
dash_info_color: this.dash_info_color,
|
|
||||||
dash_positive_color: this.dash_positive_color,
|
|
||||||
dash_negative_color: this.dash_negative_color,
|
|
||||||
dash_warning_color: this.dash_warning_color,
|
|
||||||
clear_search_when_switching: this.clear_search_when_switching,
|
clear_search_when_switching: this.clear_search_when_switching,
|
||||||
date_format: this.date_format,
|
date_format: this.date_format,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
ref="dialogRef"
|
ref="dialogRef"
|
||||||
@hide="onDialogHide"
|
@hide="onDialogHide"
|
||||||
persistent
|
persistent
|
||||||
@keydown.esc.stop="onDialogHide"
|
@keydown.esc="onDialogHide"
|
||||||
:maximized="maximized"
|
:maximized="maximized"
|
||||||
>
|
>
|
||||||
<q-card
|
<q-card
|
||||||
@@ -11,17 +11,7 @@
|
|||||||
:style="maximized ? '' : 'width: 90vw; max-width: 90vw'"
|
:style="maximized ? '' : 'width: 90vw; max-width: 90vw'"
|
||||||
>
|
>
|
||||||
<q-bar>
|
<q-bar>
|
||||||
<span class="q-pr-sm">{{ title }}</span>
|
{{ title }}
|
||||||
<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
|
||||||
@@ -67,133 +57,116 @@
|
|||||||
><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">
|
||||||
<q-scroll-area
|
<div class="col-4 q-gutter-sm q-pr-sm">
|
||||||
:thumb-style="{
|
<q-input
|
||||||
right: '4px',
|
filled
|
||||||
borderRadius: '5px',
|
dense
|
||||||
width: '5px',
|
:readonly="readonly"
|
||||||
opacity: 0.75,
|
v-model="formScript.name"
|
||||||
}"
|
label="Name"
|
||||||
:bar-style="{
|
:rules="[(val) => !!val || '*Required']"
|
||||||
right: '2px',
|
hide-bottom-space
|
||||||
borderRadius: '9px',
|
/>
|
||||||
width: '9px',
|
<q-input
|
||||||
opacity: 0.2,
|
filled
|
||||||
}"
|
dense
|
||||||
class="col-4 q-mb-none q-pb-none"
|
:readonly="readonly"
|
||||||
:style="{ height: `${maximized ? '82vh' : '64vh'}` }"
|
v-model="formScript.description"
|
||||||
>
|
label="Description"
|
||||||
<div class="q-gutter-sm q-pr-sm">
|
/>
|
||||||
<q-input
|
<q-select
|
||||||
filled
|
:readonly="readonly"
|
||||||
dense
|
options-dense
|
||||||
:readonly="readonly"
|
filled
|
||||||
v-model="formScript.name"
|
dense
|
||||||
label="Name"
|
v-model="formScript.shell"
|
||||||
:rules="[(val) => !!val || '*Required']"
|
:options="shellOptions"
|
||||||
hide-bottom-space
|
emit-value
|
||||||
/>
|
map-options
|
||||||
<q-input
|
label="Shell Type"
|
||||||
filled
|
/>
|
||||||
dense
|
<tactical-dropdown
|
||||||
:readonly="readonly"
|
v-model="formScript.supported_platforms"
|
||||||
v-model="formScript.description"
|
:options="agentPlatformOptions"
|
||||||
label="Description"
|
label="Supported Platforms (All supported if blank)"
|
||||||
/>
|
clearable
|
||||||
<q-select
|
mapOptions
|
||||||
:readonly="readonly"
|
filled
|
||||||
options-dense
|
multiple
|
||||||
filled
|
:readonly="readonly"
|
||||||
dense
|
/>
|
||||||
v-model="formScript.shell"
|
<tactical-dropdown
|
||||||
:options="shellOptions"
|
filled
|
||||||
emit-value
|
v-model="formScript.category"
|
||||||
map-options
|
:options="categories"
|
||||||
label="Shell Type"
|
use-input
|
||||||
/>
|
clearable
|
||||||
<tactical-dropdown
|
new-value-mode="add-unique"
|
||||||
v-model="formScript.supported_platforms"
|
filterable
|
||||||
:options="agentPlatformOptions"
|
label="Category"
|
||||||
label="Supported Platforms (All supported if blank)"
|
:readonly="readonly"
|
||||||
clearable
|
hide-bottom-space
|
||||||
mapOptions
|
/>
|
||||||
filled
|
<tactical-dropdown
|
||||||
multiple
|
v-model="formScript.args"
|
||||||
:readonly="readonly"
|
label="Script Arguments (press Enter after typing each argument)"
|
||||||
/>
|
filled
|
||||||
<tactical-dropdown
|
use-input
|
||||||
filled
|
multiple
|
||||||
v-model="formScript.category"
|
hide-dropdown-icon
|
||||||
:options="categories"
|
input-debounce="0"
|
||||||
use-input
|
new-value-mode="add"
|
||||||
clearable
|
:readonly="readonly"
|
||||||
new-value-mode="add-unique"
|
/>
|
||||||
filterable
|
<tactical-dropdown
|
||||||
label="Category"
|
v-model="formScript.env_vars"
|
||||||
:readonly="readonly"
|
:label="envVarsLabel"
|
||||||
hide-bottom-space
|
filled
|
||||||
/>
|
use-input
|
||||||
<tactical-dropdown
|
multiple
|
||||||
v-model="formScript.args"
|
hide-dropdown-icon
|
||||||
label="Script Arguments (press Enter after typing each argument)"
|
input-debounce="0"
|
||||||
filled
|
new-value-mode="add"
|
||||||
use-input
|
:readonly="readonly"
|
||||||
multiple
|
/>
|
||||||
hide-dropdown-icon
|
<q-input
|
||||||
input-debounce="0"
|
type="number"
|
||||||
new-value-mode="add"
|
filled
|
||||||
:readonly="readonly"
|
dense
|
||||||
/>
|
:readonly="readonly"
|
||||||
<tactical-dropdown
|
v-model.number="formScript.default_timeout"
|
||||||
v-model="formScript.env_vars"
|
label="Timeout (seconds)"
|
||||||
:label="envVarsLabel"
|
:rules="[(val) => val >= 5 || 'Minimum is 5']"
|
||||||
filled
|
hide-bottom-space
|
||||||
use-input
|
/>
|
||||||
multiple
|
<q-checkbox
|
||||||
hide-dropdown-icon
|
v-model="formScript.run_as_user"
|
||||||
input-debounce="0"
|
label="Run As User (Windows only)"
|
||||||
new-value-mode="add"
|
>
|
||||||
:readonly="readonly"
|
<q-tooltip
|
||||||
/>
|
>Setting this value on the script model will always override any
|
||||||
<q-input
|
'Run As User' checkboxes in the UI and force this script to
|
||||||
type="number"
|
always be run in the context of the logged in user. If no user
|
||||||
filled
|
is logged in, the script will not run and an error will be
|
||||||
dense
|
returned.
|
||||||
:readonly="readonly"
|
</q-tooltip>
|
||||||
v-model.number="formScript.default_timeout"
|
</q-checkbox>
|
||||||
label="Timeout (seconds)"
|
<q-input
|
||||||
:rules="[(val) => val >= 5 || 'Minimum is 5']"
|
label="Syntax"
|
||||||
hide-bottom-space
|
type="textarea"
|
||||||
/>
|
style="height: 150px; overflow-y: auto; resize: none"
|
||||||
<q-checkbox
|
v-model="formScript.syntax"
|
||||||
v-model="formScript.run_as_user"
|
dense
|
||||||
label="Run As User (Windows only)"
|
filled
|
||||||
>
|
:readonly="readonly"
|
||||||
<q-tooltip
|
/>
|
||||||
>Setting this value on the script model will always override
|
</div>
|
||||||
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 ? '82vh' : '64vh'}` }"
|
:style="{ height: `${maximized ? '87vh' : '64vh'}` }"
|
||||||
wrap
|
wrap
|
||||||
:printMargin="false"
|
:printMargin="false"
|
||||||
:options="{ fontSize: '14px' }"
|
:options="{ fontSize: '14px' }"
|
||||||
@@ -247,11 +220,9 @@
|
|||||||
<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
|
||||||
@@ -295,10 +266,6 @@ 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();
|
||||||
|
|
||||||
@@ -388,23 +355,6 @@ 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;
|
||||||
@@ -430,12 +380,10 @@ export default {
|
|||||||
|
|
||||||
//computed
|
//computed
|
||||||
title,
|
title,
|
||||||
openAIEnabled,
|
|
||||||
|
|
||||||
//methods
|
//methods
|
||||||
submitForm,
|
submitForm,
|
||||||
openTestScriptModal,
|
openTestScriptModal,
|
||||||
generateScriptOpenAI,
|
|
||||||
|
|
||||||
// quasar dialog plugin
|
// quasar dialog plugin
|
||||||
dialogRef,
|
dialogRef,
|
||||||
|
|||||||
@@ -286,10 +286,15 @@
|
|||||||
</template>
|
</template>
|
||||||
</q-tree>
|
</q-tree>
|
||||||
</div>
|
</div>
|
||||||
<tactical-table
|
<q-table
|
||||||
v-if="tableView"
|
v-if="tableView"
|
||||||
dense
|
dense
|
||||||
|
:table-class="{
|
||||||
|
'table-bgcolor': !$q.dark.isActive,
|
||||||
|
'table-bgcolor-dark': $q.dark.isActive,
|
||||||
|
}"
|
||||||
:style="{ 'max-height': `${$q.screen.height - 182}px` }"
|
:style="{ 'max-height': `${$q.screen.height - 182}px` }"
|
||||||
|
class="tbl-sticky"
|
||||||
:rows="visibleScripts"
|
:rows="visibleScripts"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
@@ -299,7 +304,6 @@
|
|||||||
binary-state-sort
|
binary-state-sort
|
||||||
virtual-scroll
|
virtual-scroll
|
||||||
:rows-per-page-options="[0]"
|
:rows-per-page-options="[0]"
|
||||||
column-select
|
|
||||||
>
|
>
|
||||||
<template v-slot:header-cell-favorite="props">
|
<template v-slot:header-cell-favorite="props">
|
||||||
<q-th :props="props" auto-width>
|
<q-th :props="props" auto-width>
|
||||||
@@ -421,7 +425,7 @@
|
|||||||
</q-list>
|
</q-list>
|
||||||
</q-menu>
|
</q-menu>
|
||||||
<!-- favorite -->
|
<!-- favorite -->
|
||||||
<q-td key="favorite" :props="props">
|
<q-td>
|
||||||
<q-icon
|
<q-icon
|
||||||
v-if="props.row.favorite"
|
v-if="props.row.favorite"
|
||||||
color="yellow-8"
|
color="yellow-8"
|
||||||
@@ -430,7 +434,7 @@
|
|||||||
/>
|
/>
|
||||||
</q-td>
|
</q-td>
|
||||||
<!-- shell icon -->
|
<!-- shell icon -->
|
||||||
<q-td key="shell" :props="props">
|
<q-td>
|
||||||
<q-icon
|
<q-icon
|
||||||
v-if="props.row.shell === 'powershell'"
|
v-if="props.row.shell === 'powershell'"
|
||||||
name="mdi-powershell"
|
name="mdi-powershell"
|
||||||
@@ -465,7 +469,7 @@
|
|||||||
</q-icon>
|
</q-icon>
|
||||||
</q-td>
|
</q-td>
|
||||||
<!-- supported platforms -->
|
<!-- supported platforms -->
|
||||||
<q-td key="supported_platforms" :props="props">
|
<q-td>
|
||||||
<q-badge
|
<q-badge
|
||||||
v-if="
|
v-if="
|
||||||
!props.row.supported_platforms ||
|
!props.row.supported_platforms ||
|
||||||
@@ -483,11 +487,7 @@
|
|||||||
>
|
>
|
||||||
</q-td>
|
</q-td>
|
||||||
<!-- name -->
|
<!-- name -->
|
||||||
<q-td
|
<q-td :style="{ color: props.row.hidden ? 'grey' : '' }">
|
||||||
key="name"
|
|
||||||
:props="props"
|
|
||||||
:style="{ color: props.row.hidden ? 'grey' : '' }"
|
|
||||||
>
|
|
||||||
{{ 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"
|
||||||
@@ -497,7 +497,7 @@
|
|||||||
</q-tooltip>
|
</q-tooltip>
|
||||||
</q-td>
|
</q-td>
|
||||||
<!-- args -->
|
<!-- args -->
|
||||||
<q-td key="args" :props="props">
|
<q-td>
|
||||||
<span v-if="props.row.args.length > 0">
|
<span v-if="props.row.args.length > 0">
|
||||||
{{ truncateText(props.row.args.toString(), 30) }}
|
{{ truncateText(props.row.args.toString(), 30) }}
|
||||||
<q-tooltip
|
<q-tooltip
|
||||||
@@ -509,8 +509,8 @@
|
|||||||
</span>
|
</span>
|
||||||
</q-td>
|
</q-td>
|
||||||
|
|
||||||
<q-td key="category" :props="props">{{ props.row.category }}</q-td>
|
<q-td>{{ props.row.category }}</q-td>
|
||||||
<q-td key="desc" :props="props">
|
<q-td>
|
||||||
{{ truncateText(props.row.description, 30) }}
|
{{ truncateText(props.row.description, 30) }}
|
||||||
<q-tooltip
|
<q-tooltip
|
||||||
v-if="props.row.description.length >= 30"
|
v-if="props.row.description.length >= 30"
|
||||||
@@ -518,13 +518,10 @@
|
|||||||
>{{ props.row.description }}</q-tooltip
|
>{{ props.row.description }}</q-tooltip
|
||||||
>
|
>
|
||||||
</q-td>
|
</q-td>
|
||||||
<q-td key="default_timeout" :props="props">{{
|
<q-td>{{ props.row.default_timeout }}</q-td>
|
||||||
props.row.default_timeout
|
|
||||||
}}</q-td>
|
|
||||||
<q-td></q-td>
|
|
||||||
</q-tr>
|
</q-tr>
|
||||||
</template>
|
</template>
|
||||||
</tactical-table>
|
</q-table>
|
||||||
</q-card>
|
</q-card>
|
||||||
</q-dialog>
|
</q-dialog>
|
||||||
</template>
|
</template>
|
||||||
@@ -548,13 +545,12 @@ import { notifySuccess } from "@/utils/notify";
|
|||||||
import ScriptUploadModal from "@/components/scripts/ScriptUploadModal.vue";
|
import ScriptUploadModal from "@/components/scripts/ScriptUploadModal.vue";
|
||||||
import ScriptFormModal from "@/components/scripts/ScriptFormModal.vue";
|
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";
|
|
||||||
|
|
||||||
// static data
|
// static data
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
name: "favorite",
|
name: "favorite",
|
||||||
label: "Favorites",
|
label: "",
|
||||||
field: "favorite",
|
field: "favorite",
|
||||||
align: "left",
|
align: "left",
|
||||||
sortable: true,
|
sortable: true,
|
||||||
@@ -612,9 +608,6 @@ const columns = [
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "ScriptManager",
|
name: "ScriptManager",
|
||||||
components: {
|
|
||||||
TacticalTable,
|
|
||||||
},
|
|
||||||
emits: [...useDialogPluginComponent.emits],
|
emits: [...useDialogPluginComponent.emits],
|
||||||
setup() {
|
setup() {
|
||||||
// setup vuex store
|
// setup vuex store
|
||||||
|
|||||||
@@ -11,17 +11,7 @@
|
|||||||
:style="maximized ? '' : 'width: 70vw; max-width: 90vw'"
|
:style="maximized ? '' : 'width: 70vw; max-width: 90vw'"
|
||||||
>
|
>
|
||||||
<q-bar>
|
<q-bar>
|
||||||
<span class="q-pr-sm">{{ title }}</span>
|
{{ title }}
|
||||||
<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
|
||||||
@@ -107,9 +97,6 @@
|
|||||||
<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";
|
||||||
@@ -141,13 +128,6 @@ 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))
|
||||||
@@ -187,23 +167,6 @@ 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,
|
||||||
@@ -216,11 +179,9 @@ export default {
|
|||||||
|
|
||||||
//computed
|
//computed
|
||||||
title,
|
title,
|
||||||
openAIEnabled,
|
|
||||||
|
|
||||||
//methods
|
//methods
|
||||||
submitForm,
|
submitForm,
|
||||||
generateScriptOpenAI,
|
|
||||||
|
|
||||||
// quasar dialog plugin
|
// quasar dialog plugin
|
||||||
dialogRef,
|
dialogRef,
|
||||||
|
|||||||
@@ -1,107 +0,0 @@
|
|||||||
<template>
|
|
||||||
<q-table
|
|
||||||
:columns="localColumns"
|
|
||||||
:visible-columns="visibleColumns"
|
|
||||||
:table-class="{
|
|
||||||
'table-bgcolor': !$q.dark.isActive,
|
|
||||||
'table-bgcolor-dark': $q.dark.isActive,
|
|
||||||
'column-bgcolor-dark': $q.dark.isActive && columnSelect,
|
|
||||||
'column-bgcolor': !$q.dark.isActive && columnSelect,
|
|
||||||
'sticky-header-right-column': columnSelect,
|
|
||||||
'tbl-sticky': !columnSelect,
|
|
||||||
}"
|
|
||||||
v-bind="$attrs"
|
|
||||||
>
|
|
||||||
<template v-for="(_, slot) in $slots" v-slot:[slot]="scope">
|
|
||||||
<slot :name="slot" v-bind="scope || {}" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-slot:header-cell-columnSelect="props">
|
|
||||||
<q-th :props="props" auto-width>
|
|
||||||
<q-btn dense flat icon="more_horiz">
|
|
||||||
<q-menu>
|
|
||||||
<q-option-group
|
|
||||||
v-model="visibleColumns"
|
|
||||||
:options="columnOptions"
|
|
||||||
type="checkbox"
|
|
||||||
/>
|
|
||||||
</q-menu>
|
|
||||||
</q-btn>
|
|
||||||
</q-th>
|
|
||||||
</template>
|
|
||||||
</q-table>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from "vue";
|
|
||||||
export default defineComponent({
|
|
||||||
inheritAttrs: false,
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref } from "vue";
|
|
||||||
import { type QTableColumn } from "quasar";
|
|
||||||
const props = withDefaults(
|
|
||||||
defineProps<{
|
|
||||||
columns: QTableColumn[];
|
|
||||||
columnSelect?: boolean;
|
|
||||||
excludeColumns?: string[];
|
|
||||||
}>(),
|
|
||||||
{ columnSelect: false, excludeColumns: () => ["columnSelect"] }
|
|
||||||
);
|
|
||||||
// save a non-reactive copy of columns to modify
|
|
||||||
const localColumns: QTableColumn[] = Object.assign([], props.columns);
|
|
||||||
if (props.columnSelect)
|
|
||||||
localColumns.push({
|
|
||||||
name: "columnSelect",
|
|
||||||
label: "Column Select",
|
|
||||||
field: "columnSelect",
|
|
||||||
});
|
|
||||||
const visibleColumns = ref(localColumns.map((column) => column.name));
|
|
||||||
const columnOptions = ref(
|
|
||||||
localColumns
|
|
||||||
.filter((column) => !props.excludeColumns.includes(column.name))
|
|
||||||
.map((column) => ({ label: column.label, value: column.name }))
|
|
||||||
);
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="sass">
|
|
||||||
|
|
||||||
.column-bgcolor-dark
|
|
||||||
td:last-child
|
|
||||||
/* bg color is important for td; just specify one */
|
|
||||||
background-color: #1d1d1d
|
|
||||||
|
|
||||||
.column-bgcolor
|
|
||||||
td:last-child
|
|
||||||
/* bg color is important for td; just specify one */
|
|
||||||
background-color: #ffffff
|
|
||||||
|
|
||||||
.sticky-header-right-column
|
|
||||||
tr th
|
|
||||||
position: sticky
|
|
||||||
/* higher than z-index for td below */
|
|
||||||
z-index: 2
|
|
||||||
/* this will be the loading indicator */
|
|
||||||
thead tr:last-child th
|
|
||||||
/* height of all previous header rows */
|
|
||||||
top: 48px
|
|
||||||
/* highest z-index */
|
|
||||||
z-index: 3
|
|
||||||
thead tr:last-child th
|
|
||||||
top: 0
|
|
||||||
z-index: 1
|
|
||||||
tr:last-child th:last-child
|
|
||||||
/* highest z-index */
|
|
||||||
z-index: 3
|
|
||||||
td:last-child
|
|
||||||
z-index: 1
|
|
||||||
td:last-child, th:last-child
|
|
||||||
position: sticky
|
|
||||||
right: 0
|
|
||||||
/* prevent scrolling behind sticky top row on focus */
|
|
||||||
tbody
|
|
||||||
/* height of all previous header rows */
|
|
||||||
scroll-margin-top: 48px
|
|
||||||
</style>
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import { computed, ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { useStore } from "vuex";
|
|
||||||
import { fetchAgents } from "@/api/agents";
|
import { fetchAgents } from "@/api/agents";
|
||||||
import { formatAgentOptions } from "@/utils/format";
|
import { formatAgentOptions } from "@/utils/format";
|
||||||
|
|
||||||
@@ -29,12 +28,10 @@ export function useAgentDropdown() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function cmdPlaceholder(shell) {
|
export function cmdPlaceholder(shell) {
|
||||||
const store = useStore();
|
if (shell === "cmd") return "rmdir /S /Q C:\\Windows\\System32";
|
||||||
const placeholders = computed(() => store.state.run_cmd_placeholder_text);
|
else if (shell === "powershell")
|
||||||
|
return "Remove-Item -Recurse -Force C:\\Windows\\System32";
|
||||||
if (shell === "cmd") return placeholders.value.cmd;
|
else return "rm -rf --no-preserve-root /";
|
||||||
else if (shell === "powershell") return placeholders.value.powershell;
|
|
||||||
else return placeholders.value.shell;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const agentPlatformOptions = [
|
export const agentPlatformOptions = [
|
||||||
|
|||||||
@@ -56,27 +56,15 @@
|
|||||||
Tactical RMM<span class="text-overline q-ml-sm"
|
Tactical RMM<span class="text-overline q-ml-sm"
|
||||||
>v{{ currentTRMMVersion }}</span
|
>v{{ currentTRMMVersion }}</span
|
||||||
>
|
>
|
||||||
<!-- update check -->
|
<span class="text-overline q-ml-md" v-if="updateAvailable()"
|
||||||
<q-chip
|
><q-badge color="warning"
|
||||||
v-if="updateAvailable"
|
><a :href="latestReleaseURL" target="_blank"
|
||||||
class="text-overline q-ml-sm"
|
>v{{ latestTRMMVersion }} available</a
|
||||||
:color="dash_warning_color"
|
></q-badge
|
||||||
icon="update"
|
></span
|
||||||
dense
|
|
||||||
><a :href="latestReleaseURL" target="_blank"
|
|
||||||
>v{{ latestTRMMVersion }} available</a
|
|
||||||
></q-chip
|
|
||||||
>
|
|
||||||
<!-- cert expiring soon check -->
|
|
||||||
<q-chip
|
|
||||||
v-if="daysUntilCertExpires <= 15"
|
|
||||||
dense
|
|
||||||
:color="dash_negative_color"
|
|
||||||
text-color="black"
|
|
||||||
icon="warning"
|
|
||||||
>Certificate expires in {{ daysUntilCertExpires }} days</q-chip
|
|
||||||
>
|
>
|
||||||
</q-toolbar-title>
|
</q-toolbar-title>
|
||||||
|
|
||||||
<!-- temp dark mode toggle -->
|
<!-- temp dark mode toggle -->
|
||||||
<q-toggle
|
<q-toggle
|
||||||
v-model="darkMode"
|
v-model="darkMode"
|
||||||
@@ -106,11 +94,7 @@
|
|||||||
</q-item>
|
</q-item>
|
||||||
<q-item>
|
<q-item>
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
<q-icon
|
<q-icon name="power_off" size="sm" color="negative" />
|
||||||
name="power_off"
|
|
||||||
size="sm"
|
|
||||||
:color="dash_negative_color"
|
|
||||||
/>
|
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
|
|
||||||
<q-item-section no-wrap>
|
<q-item-section no-wrap>
|
||||||
@@ -129,11 +113,7 @@
|
|||||||
</q-item>
|
</q-item>
|
||||||
<q-item>
|
<q-item>
|
||||||
<q-item-section avatar>
|
<q-item-section avatar>
|
||||||
<q-icon
|
<q-icon name="power_off" size="sm" color="negative" />
|
||||||
name="power_off"
|
|
||||||
size="sm"
|
|
||||||
:color="dash_negative_color"
|
|
||||||
/>
|
|
||||||
</q-item-section>
|
</q-item-section>
|
||||||
|
|
||||||
<q-item-section no-wrap>
|
<q-item-section no-wrap>
|
||||||
@@ -238,8 +218,6 @@ export default {
|
|||||||
const user = computed(() => store.state.username);
|
const user = computed(() => store.state.username);
|
||||||
const hosted = computed(() => store.state.hosted);
|
const hosted = computed(() => store.state.hosted);
|
||||||
const tokenExpired = computed(() => store.state.tokenExpired);
|
const tokenExpired = computed(() => store.state.tokenExpired);
|
||||||
const dash_warning_color = computed(() => store.state.dash_warning_color);
|
|
||||||
const dash_negative_color = computed(() => store.state.dash_negative_color);
|
|
||||||
|
|
||||||
const latestReleaseURL = computed(() => {
|
const latestReleaseURL = computed(() => {
|
||||||
return latestTRMMVersion.value
|
return latestTRMMVersion.value
|
||||||
@@ -277,7 +255,6 @@ export default {
|
|||||||
const serverOfflineCount = ref(0);
|
const serverOfflineCount = ref(0);
|
||||||
const workstationCount = ref(0);
|
const workstationCount = ref(0);
|
||||||
const workstationOfflineCount = ref(0);
|
const workstationOfflineCount = ref(0);
|
||||||
const daysUntilCertExpires = ref(100);
|
|
||||||
|
|
||||||
const ws = ref(null);
|
const ws = ref(null);
|
||||||
|
|
||||||
@@ -285,13 +262,6 @@ export default {
|
|||||||
// moved computed token inside the function since it is not refreshing
|
// moved computed token inside the function since it is not refreshing
|
||||||
// when ws is closed causing ws to connect with expired token
|
// when ws is closed causing ws to connect with expired token
|
||||||
const token = computed(() => store.state.token);
|
const token = computed(() => store.state.token);
|
||||||
|
|
||||||
if (!token.value) {
|
|
||||||
console.log(
|
|
||||||
"Access token is null or invalid, not setting up WebSocket"
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.log("Starting websocket");
|
console.log("Starting websocket");
|
||||||
let url = getWSUrl("dashinfo", token.value);
|
let url = getWSUrl("dashinfo", token.value);
|
||||||
ws.value = new WebSocket(url);
|
ws.value = new WebSocket(url);
|
||||||
@@ -304,7 +274,6 @@ export default {
|
|||||||
serverOfflineCount.value = data.total_server_offline_count;
|
serverOfflineCount.value = data.total_server_offline_count;
|
||||||
workstationCount.value = data.total_workstation_count;
|
workstationCount.value = data.total_workstation_count;
|
||||||
workstationOfflineCount.value = data.total_workstation_offline_count;
|
workstationOfflineCount.value = data.total_workstation_offline_count;
|
||||||
daysUntilCertExpires.value = data.days_until_cert_expires;
|
|
||||||
};
|
};
|
||||||
ws.value.onclose = (e) => {
|
ws.value.onclose = (e) => {
|
||||||
try {
|
try {
|
||||||
@@ -328,18 +297,13 @@ export default {
|
|||||||
poll.value = setInterval(() => {
|
poll.value = setInterval(() => {
|
||||||
store.dispatch("checkVer");
|
store.dispatch("checkVer");
|
||||||
store.dispatch("getDashInfo", false);
|
store.dispatch("getDashInfo", false);
|
||||||
}, 60 * 4 * 1000);
|
}, 60 * 5 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateAvailable = computed(() => {
|
function updateAvailable() {
|
||||||
if (
|
if (latestTRMMVersion.value === "error" || hosted.value) return false;
|
||||||
latestTRMMVersion.value === "error" ||
|
|
||||||
hosted.value ||
|
|
||||||
currentTRMMVersion.value?.includes("-dev")
|
|
||||||
)
|
|
||||||
return false;
|
|
||||||
return currentTRMMVersion.value !== latestTRMMVersion.value;
|
return currentTRMMVersion.value !== latestTRMMVersion.value;
|
||||||
});
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
setupWS();
|
setupWS();
|
||||||
@@ -360,7 +324,6 @@ export default {
|
|||||||
serverOfflineCount,
|
serverOfflineCount,
|
||||||
workstationCount,
|
workstationCount,
|
||||||
workstationOfflineCount,
|
workstationOfflineCount,
|
||||||
daysUntilCertExpires,
|
|
||||||
latestReleaseURL,
|
latestReleaseURL,
|
||||||
currentTRMMVersion,
|
currentTRMMVersion,
|
||||||
latestTRMMVersion,
|
latestTRMMVersion,
|
||||||
@@ -369,8 +332,6 @@ export default {
|
|||||||
darkMode,
|
darkMode,
|
||||||
hosted,
|
hosted,
|
||||||
tokenExpired,
|
tokenExpired,
|
||||||
dash_warning_color,
|
|
||||||
dash_negative_color,
|
|
||||||
|
|
||||||
// methods
|
// methods
|
||||||
showUserPreferences,
|
showUserPreferences,
|
||||||
|
|||||||
@@ -33,16 +33,6 @@ 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,
|
|
||||||
dash_info_color: "info",
|
|
||||||
dash_positive_color: "positive",
|
|
||||||
dash_negative_color: "negative",
|
|
||||||
dash_warning_color: "warning",
|
|
||||||
run_cmd_placeholder_text: {
|
|
||||||
cmd: "rmdir /S /Q C:\\Windows\\System32",
|
|
||||||
powershell: "Remove-Item -Recurse -Force C:\\Windows\\System32",
|
|
||||||
shell: "rm -rf --no-preserve-root /",
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
@@ -146,24 +136,6 @@ export default function () {
|
|||||||
setDateFormat(state, val) {
|
setDateFormat(state, val) {
|
||||||
state.dateFormat = val;
|
state.dateFormat = val;
|
||||||
},
|
},
|
||||||
setOpenAIIntegrationStatus(state, val) {
|
|
||||||
state.openAIIntegrationEnabled = val;
|
|
||||||
},
|
|
||||||
setDashInfoColor(state, val) {
|
|
||||||
state.dash_info_color = val;
|
|
||||||
},
|
|
||||||
setDashPositiveColor(state, val) {
|
|
||||||
state.dash_positive_color = val;
|
|
||||||
},
|
|
||||||
setDashNegativeColor(state, val) {
|
|
||||||
state.dash_negative_color = val;
|
|
||||||
},
|
|
||||||
setDashWarningColor(state, val) {
|
|
||||||
state.dash_warning_color = val;
|
|
||||||
},
|
|
||||||
setRunCmdPlaceholders(state, obj) {
|
|
||||||
state.run_cmd_placeholder_text = obj;
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
setClientTreeSplitter(context, val) {
|
setClientTreeSplitter(context, val) {
|
||||||
@@ -188,9 +160,9 @@ export default function () {
|
|||||||
}
|
}
|
||||||
if (clearTreeSelected) commit("destroySubTable");
|
if (clearTreeSelected) commit("destroySubTable");
|
||||||
|
|
||||||
dispatch("getDashInfo", false);
|
|
||||||
dispatch("loadAgents");
|
dispatch("loadAgents");
|
||||||
dispatch("loadTree");
|
dispatch("loadTree");
|
||||||
|
dispatch("getDashInfo", false);
|
||||||
},
|
},
|
||||||
async loadAgents({ state, commit }) {
|
async loadAgents({ state, commit }) {
|
||||||
commit("AGENT_TABLE_LOADING", true);
|
commit("AGENT_TABLE_LOADING", true);
|
||||||
@@ -222,111 +194,107 @@ export default function () {
|
|||||||
|
|
||||||
commit("AGENT_TABLE_LOADING", false);
|
commit("AGENT_TABLE_LOADING", false);
|
||||||
},
|
},
|
||||||
async getDashInfo({ commit }, edited = true) {
|
async getDashInfo(context, edited = true) {
|
||||||
const { data } = await axios.get("/core/dashinfo/");
|
const { data } = await axios.get("/core/dashinfo/");
|
||||||
commit("setDashInfoColor", data.dash_info_color);
|
|
||||||
commit("setDashPositiveColor", data.dash_positive_color);
|
|
||||||
commit("setDashNegativeColor", data.dash_negative_color);
|
|
||||||
commit("setDashWarningColor", data.dash_warning_color);
|
|
||||||
if (edited) {
|
if (edited) {
|
||||||
LoadingBar.setDefaults({ color: data.loading_bar_color });
|
LoadingBar.setDefaults({ color: data.loading_bar_color });
|
||||||
commit(
|
context.commit(
|
||||||
"setClearSearchWhenSwitching",
|
"setClearSearchWhenSwitching",
|
||||||
data.clear_search_when_switching
|
data.clear_search_when_switching
|
||||||
);
|
);
|
||||||
commit("SET_DEFAULT_AGENT_TBL_TAB", data.default_agent_tbl_tab);
|
context.commit(
|
||||||
commit("SET_CLIENT_TREE_SORT", data.client_tree_sort);
|
"SET_DEFAULT_AGENT_TBL_TAB",
|
||||||
commit("SET_CLIENT_SPLITTER", data.client_tree_splitter);
|
data.default_agent_tbl_tab
|
||||||
|
);
|
||||||
|
context.commit("SET_CLIENT_TREE_SORT", data.client_tree_sort);
|
||||||
|
context.commit("SET_CLIENT_SPLITTER", data.client_tree_splitter);
|
||||||
}
|
}
|
||||||
Dark.set(data.dark_mode);
|
Dark.set(data.dark_mode);
|
||||||
commit("setCurrentTRMMVersion", data.trmm_version);
|
context.commit("setCurrentTRMMVersion", data.trmm_version);
|
||||||
commit("setLatestTRMMVersion", data.latest_trmm_ver);
|
context.commit("setLatestTRMMVersion", data.latest_trmm_ver);
|
||||||
commit("SET_AGENT_DBLCLICK_ACTION", data.dbl_click_action);
|
context.commit("SET_AGENT_DBLCLICK_ACTION", data.dbl_click_action);
|
||||||
commit("SET_URL_ACTION", data.url_action);
|
context.commit("SET_URL_ACTION", data.url_action);
|
||||||
commit("setShowCommunityScripts", data.show_community_scripts);
|
context.commit("setShowCommunityScripts", data.show_community_scripts);
|
||||||
commit("SET_HOSTED", data.hosted);
|
context.commit("SET_HOSTED", data.hosted);
|
||||||
commit("SET_TOKEN_EXPIRED", data.token_is_expired);
|
context.commit("SET_TOKEN_EXPIRED", data.token_is_expired);
|
||||||
commit("setOpenAIIntegrationStatus", data.open_ai_integration_enabled);
|
|
||||||
commit("setRunCmdPlaceholders", data.run_cmd_placeholder_text);
|
|
||||||
|
|
||||||
if (data?.date_format !== "") commit("setDateFormat", data.date_format);
|
if (data.date_format && data.date_format !== "")
|
||||||
else commit("setDateFormat", data.default_date_format);
|
context.commit("setDateFormat", data.date_format);
|
||||||
|
else context.commit("setDateFormat", data.default_date_format);
|
||||||
},
|
},
|
||||||
loadTree({ commit, state }) {
|
loadTree({ commit, state }) {
|
||||||
setTimeout(() => {
|
axios
|
||||||
axios
|
.get("/clients/")
|
||||||
.get("/clients/")
|
.then((r) => {
|
||||||
.then((r) => {
|
if (r.data.length === 0) {
|
||||||
if (r.data.length === 0) {
|
this.$router.push({ name: "InitialSetup" });
|
||||||
this.$router.push({ name: "InitialSetup" });
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let output = [];
|
let output = [];
|
||||||
for (let client of r.data) {
|
for (let client of r.data) {
|
||||||
let childSites = [];
|
let childSites = [];
|
||||||
for (let site of client.sites) {
|
for (let site of client.sites) {
|
||||||
let siteNode = {
|
let siteNode = {
|
||||||
label: site.name,
|
label: site.name,
|
||||||
id: site.id,
|
id: site.id,
|
||||||
raw: `Site|${site.id}`,
|
raw: `Site|${site.id}`,
|
||||||
header: "generic",
|
header: "generic",
|
||||||
icon: "apartment",
|
icon: "apartment",
|
||||||
selectable: true,
|
selectable: true,
|
||||||
site: site,
|
site: site,
|
||||||
};
|
|
||||||
|
|
||||||
if (site.maintenance_mode) {
|
|
||||||
siteNode["color"] = "green";
|
|
||||||
} else if (site.failing_checks.error) {
|
|
||||||
siteNode["color"] = "negative";
|
|
||||||
} else if (site.failing_checks.warning) {
|
|
||||||
siteNode["color"] = "warning";
|
|
||||||
}
|
|
||||||
|
|
||||||
childSites.push(siteNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
let clientNode = {
|
|
||||||
label: client.name,
|
|
||||||
id: client.id,
|
|
||||||
raw: `Client|${client.id}`,
|
|
||||||
header: "root",
|
|
||||||
icon: "business",
|
|
||||||
children: childSites,
|
|
||||||
client: client,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (client.maintenance_mode) clientNode["color"] = "green";
|
if (site.maintenance_mode) {
|
||||||
else if (client.failing_checks.error) {
|
siteNode["color"] = "green";
|
||||||
clientNode["color"] = "negative";
|
} else if (site.failing_checks.error) {
|
||||||
} else if (client.failing_checks.warning) {
|
siteNode["color"] = "negative";
|
||||||
clientNode["color"] = "warning";
|
} else if (site.failing_checks.warning) {
|
||||||
|
siteNode["color"] = "warning";
|
||||||
}
|
}
|
||||||
|
|
||||||
output.push(clientNode);
|
childSites.push(siteNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
const sorted = output.sort((a, b) =>
|
let clientNode = {
|
||||||
a.label.localeCompare(b.label)
|
label: client.name,
|
||||||
);
|
id: client.id,
|
||||||
if (state.clientTreeSort === "alphafail") {
|
raw: `Client|${client.id}`,
|
||||||
// move failing clients to the top
|
header: "root",
|
||||||
const failing = sorted.filter(
|
icon: "business",
|
||||||
(i) => i.color === "negative" || i.color === "warning"
|
children: childSites,
|
||||||
);
|
client: client,
|
||||||
const ok = sorted.filter(
|
};
|
||||||
(i) => i.color !== "negative" && i.color !== "warning"
|
|
||||||
);
|
if (client.maintenance_mode) clientNode["color"] = "green";
|
||||||
const sortedByFailing = [...failing, ...ok];
|
else if (client.failing_checks.error) {
|
||||||
commit("loadTree", sortedByFailing);
|
clientNode["color"] = "negative";
|
||||||
} else {
|
} else if (client.failing_checks.warning) {
|
||||||
commit("loadTree", sorted);
|
clientNode["color"] = "warning";
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.catch(() => {
|
output.push(clientNode);
|
||||||
state.treeReady = true;
|
}
|
||||||
});
|
|
||||||
}, 150);
|
const sorted = output.sort((a, b) =>
|
||||||
|
a.label.localeCompare(b.label)
|
||||||
|
);
|
||||||
|
if (state.clientTreeSort === "alphafail") {
|
||||||
|
// move failing clients to the top
|
||||||
|
const failing = sorted.filter(
|
||||||
|
(i) => i.color === "negative" || i.color === "warning"
|
||||||
|
);
|
||||||
|
const ok = sorted.filter(
|
||||||
|
(i) => i.color !== "negative" && i.color !== "warning"
|
||||||
|
);
|
||||||
|
const sortedByFailing = [...failing, ...ok];
|
||||||
|
commit("loadTree", sortedByFailing);
|
||||||
|
} else {
|
||||||
|
commit("loadTree", sorted);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
state.treeReady = true;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
checkVer(context) {
|
checkVer(context) {
|
||||||
axios.get("/core/version/").then((r) => {
|
axios.get("/core/version/").then((r) => {
|
||||||
|
|||||||
@@ -452,7 +452,7 @@ export default {
|
|||||||
showInstallAgentModal: false,
|
showInstallAgentModal: false,
|
||||||
sitePk: null,
|
sitePk: null,
|
||||||
innerModel: (this.$q.screen.height - 82) / 2,
|
innerModel: (this.$q.screen.height - 82) / 2,
|
||||||
search: this.$route.query.search ? this.$route.query.search : "",
|
search: "",
|
||||||
filterTextLength: 0,
|
filterTextLength: 0,
|
||||||
filterAvailability: "all",
|
filterAvailability: "all",
|
||||||
filterPatchesPending: false,
|
filterPatchesPending: false,
|
||||||
|
|||||||
@@ -4,17 +4,8 @@
|
|||||||
<div class="col"></div>
|
<div class="col"></div>
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<q-card>
|
<q-card>
|
||||||
<q-card-actions align="center">
|
|
||||||
<q-btn
|
|
||||||
label="Getting Started"
|
|
||||||
color="info"
|
|
||||||
class="full-width"
|
|
||||||
href="https://docs.tacticalrmm.com/guide_gettingstarted/"
|
|
||||||
target="_blank"
|
|
||||||
/>
|
|
||||||
</q-card-actions>
|
|
||||||
<q-card-section class="row items-center">
|
<q-card-section class="row items-center">
|
||||||
<div class="text-h5 text-weight-bold">Initial Setup</div>
|
<div class="text-h6">Initial Setup</div>
|
||||||
</q-card-section>
|
</q-card-section>
|
||||||
<q-form @submit.prevent="finish">
|
<q-form @submit.prevent="finish">
|
||||||
<q-card-section>
|
<q-card-section>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
@click="restartMeshService"
|
@click="restartMeshService"
|
||||||
/>
|
/>
|
||||||
<q-btn
|
<q-btn
|
||||||
:color="dash_negative_color"
|
color="negative"
|
||||||
size="sm"
|
size="sm"
|
||||||
label="Recover Connection"
|
label="Recover Connection"
|
||||||
icon="fas fa-first-aid"
|
icon="fas fa-first-aid"
|
||||||
@@ -35,7 +35,6 @@
|
|||||||
<script>
|
<script>
|
||||||
// composition imports
|
// composition imports
|
||||||
import { ref, computed, onMounted } from "vue";
|
import { ref, computed, onMounted } from "vue";
|
||||||
import { useStore } from "vuex";
|
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
import { useMeta, useQuasar } from "quasar";
|
import { useMeta, useQuasar } from "quasar";
|
||||||
import { fetchAgentMeshCentralURLs, sendAgentRecoverMesh } from "@/api/agents";
|
import { fetchAgentMeshCentralURLs, sendAgentRecoverMesh } from "@/api/agents";
|
||||||
@@ -48,17 +47,12 @@ export default {
|
|||||||
setup() {
|
setup() {
|
||||||
// vue lifecycle hooks
|
// vue lifecycle hooks
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
dashInfo();
|
|
||||||
getDashInfo();
|
getDashInfo();
|
||||||
getMeshURLs();
|
getMeshURLs();
|
||||||
});
|
});
|
||||||
|
|
||||||
// quasar setup
|
// quasar setup
|
||||||
const $q = useQuasar();
|
const $q = useQuasar();
|
||||||
const store = useStore();
|
|
||||||
const dash_positive_color = computed(() => store.state.dash_positive_color);
|
|
||||||
const dash_negative_color = computed(() => store.state.dash_negative_color);
|
|
||||||
const dash_warning_color = computed(() => store.state.dash_warning_color);
|
|
||||||
|
|
||||||
// vue router
|
// vue router
|
||||||
const { params } = useRoute();
|
const { params } = useRoute();
|
||||||
@@ -70,19 +64,14 @@ export default {
|
|||||||
const statusColor = computed(() => {
|
const statusColor = computed(() => {
|
||||||
switch (status.value) {
|
switch (status.value) {
|
||||||
case "online":
|
case "online":
|
||||||
return dash_positive_color.value;
|
return "positive";
|
||||||
case "offline":
|
case "offline":
|
||||||
return dash_warning_color.value;
|
return "warning";
|
||||||
default:
|
default:
|
||||||
return dash_negative_color.value;
|
return "negative";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO refactor this so we're not calling the api twice
|
|
||||||
const dashInfo = () => {
|
|
||||||
store.dispatch("getDashInfo", false);
|
|
||||||
};
|
|
||||||
|
|
||||||
async function getMeshURLs() {
|
async function getMeshURLs() {
|
||||||
$q.loading.show();
|
$q.loading.show();
|
||||||
try {
|
try {
|
||||||
@@ -142,7 +131,6 @@ export default {
|
|||||||
control,
|
control,
|
||||||
status,
|
status,
|
||||||
statusColor,
|
statusColor,
|
||||||
dash_negative_color,
|
|
||||||
|
|
||||||
// methods
|
// methods
|
||||||
repairMeshCentral,
|
repairMeshCentral,
|
||||||
|
|||||||
Reference in New Issue
Block a user