url actions ui
This commit is contained in:
@@ -109,6 +109,30 @@
|
||||
<q-item-section>Take Control</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-item clickable v-ripple @click="getURLActions">
|
||||
<q-item-section side>
|
||||
<q-icon size="xs" name="star" />
|
||||
</q-item-section>
|
||||
<q-item-section>Run URL Action</q-item-section>
|
||||
<q-item-section side>
|
||||
<q-icon name="keyboard_arrow_right" />
|
||||
</q-item-section>
|
||||
<q-menu auto-close anchor="top end" self="top start">
|
||||
<q-list>
|
||||
<q-item
|
||||
v-for="action in urlActions"
|
||||
:key="action.id"
|
||||
dense
|
||||
clickable
|
||||
v-close-popup
|
||||
@click="runURLAction(props.row.id, action)"
|
||||
>
|
||||
{{ action.name }}
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-menu>
|
||||
</q-item>
|
||||
|
||||
<q-item clickable v-ripple v-close-popup @click="showSendCommand = true">
|
||||
<q-item-section side>
|
||||
<q-icon size="xs" name="fas fa-terminal" />
|
||||
@@ -438,6 +462,7 @@ export default {
|
||||
showPendingActions: false,
|
||||
pendingActionAgentPk: null,
|
||||
favoriteScripts: [],
|
||||
urlActions: [],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
@@ -526,17 +551,24 @@ export default {
|
||||
},
|
||||
getFavoriteScripts() {
|
||||
this.favoriteScripts = [];
|
||||
this.$axios.get("/scripts/scripts/").then(r => {
|
||||
if (r.data.filter(k => k.favorite === true).length === 0) {
|
||||
this.notifyWarning("You don't have any scripts favorited!");
|
||||
return;
|
||||
}
|
||||
this.favoriteScripts = r.data
|
||||
.filter(k => k.favorite === true)
|
||||
.map(script => ({ label: script.name, value: script.id, timeout: script.default_timeout, args: script.args }))
|
||||
.sort((a, b) => a.label.localeCompare(b.label));
|
||||
})
|
||||
.catch(e => {});
|
||||
this.$axios
|
||||
.get("/scripts/scripts/")
|
||||
.then(r => {
|
||||
if (r.data.filter(k => k.favorite === true).length === 0) {
|
||||
this.notifyWarning("You don't have any scripts favorited!");
|
||||
return;
|
||||
}
|
||||
this.favoriteScripts = r.data
|
||||
.filter(k => k.favorite === true)
|
||||
.map(script => ({
|
||||
label: script.name,
|
||||
value: script.id,
|
||||
timeout: script.default_timeout,
|
||||
args: script.args,
|
||||
}))
|
||||
.sort((a, b) => a.label.localeCompare(b.label));
|
||||
})
|
||||
.catch(e => {});
|
||||
},
|
||||
runPatchStatusScan(pk, hostname) {
|
||||
this.$axios
|
||||
@@ -740,6 +772,28 @@ export default {
|
||||
rowSelectedClass(id) {
|
||||
if (this.selectedRow === id) return this.$q.dark.isActive ? "highlight-dark" : "highlight";
|
||||
},
|
||||
getURLActions() {
|
||||
this.$axios
|
||||
.get("/core/urlaction/")
|
||||
.then(r => {
|
||||
if (r.data.length === 0) {
|
||||
this.notifyWarning("No URL Actions configured. Go to Settings > Global Settings > URL Actions");
|
||||
return;
|
||||
}
|
||||
this.urlActions = r.data;
|
||||
})
|
||||
.catch(() => {});
|
||||
},
|
||||
runURLAction(agentid, action) {
|
||||
const data = {
|
||||
agent: agentid,
|
||||
action: action.id,
|
||||
};
|
||||
this.$axios
|
||||
.patch("/core/urlaction/run", data)
|
||||
.then(r => {})
|
||||
.catch(() => {});
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(["selectedAgentPk", "agentTableHeight"]),
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<q-tab name="meshcentral" label="MeshCentral" />
|
||||
<q-tab name="customfields" label="Custom Fields" />
|
||||
<q-tab name="keystore" label="Key Store" />
|
||||
<q-tab name="urlactions" label="URL Actions" />
|
||||
</q-tabs>
|
||||
</template>
|
||||
<template v-slot:after>
|
||||
@@ -300,6 +301,10 @@
|
||||
<q-tab-panel name="keystore">
|
||||
<KeyStoreTable />
|
||||
</q-tab-panel>
|
||||
|
||||
<q-tab-panel name="urlactions">
|
||||
<URLActionsTable />
|
||||
</q-tab-panel>
|
||||
</q-tab-panels>
|
||||
</q-scroll-area>
|
||||
<q-card-section class="row items-center">
|
||||
@@ -324,12 +329,14 @@ import mixins from "@/mixins/mixins";
|
||||
import ResetPatchPolicy from "@/components/modals/coresettings/ResetPatchPolicy";
|
||||
import CustomFields from "@/components/modals/coresettings/CustomFields";
|
||||
import KeyStoreTable from "@/components/modals/coresettings/KeyStoreTable";
|
||||
import URLActionsTable from "@/components/modals/coresettings/URLActionsTable";
|
||||
|
||||
export default {
|
||||
name: "EditCoreSettings",
|
||||
components: {
|
||||
CustomFields,
|
||||
KeyStoreTable,
|
||||
URLActionsTable,
|
||||
},
|
||||
mixins: [mixins],
|
||||
data() {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<q-input label="Name" outlined dense v-model="localKey.name" :rules="[val => !!val || '*Required']" />
|
||||
</q-card-section>
|
||||
|
||||
<!-- name -->
|
||||
<!-- value -->
|
||||
<q-card-section>
|
||||
<q-input label="Value" outlined dense v-model="localKey.value" :rules="[val => !!val || '*Required']" />
|
||||
</q-card-section>
|
||||
|
||||
117
src/components/modals/coresettings/URLActionsForm.vue
Normal file
117
src/components/modals/coresettings/URLActionsForm.vue
Normal file
@@ -0,0 +1,117 @@
|
||||
<template>
|
||||
<q-dialog ref="dialog" @hide="onHide">
|
||||
<q-card class="q-dialog-plugin" style="width: 60vw">
|
||||
<q-bar>
|
||||
{{ title }}
|
||||
<q-space />
|
||||
<q-btn dense flat icon="close" v-close-popup>
|
||||
<q-tooltip content-class="bg-white text-primary">Close</q-tooltip>
|
||||
</q-btn>
|
||||
</q-bar>
|
||||
<q-form @submit="submit">
|
||||
<!-- name -->
|
||||
<q-card-section>
|
||||
<q-input label="Name" outlined dense v-model="localAction.name" :rules="[val => !!val || '*Required']" />
|
||||
</q-card-section>
|
||||
|
||||
<!-- description -->
|
||||
<q-card-section>
|
||||
<q-input label="Description" outlined dense v-model="localAction.desc" />
|
||||
</q-card-section>
|
||||
|
||||
<!-- pattern -->
|
||||
<q-card-section>
|
||||
<q-input
|
||||
label="URL Pattern"
|
||||
outlined
|
||||
dense
|
||||
v-model="localAction.pattern"
|
||||
:rules="[val => !!val || '*Required']"
|
||||
/>
|
||||
</q-card-section>
|
||||
|
||||
<q-card-actions align="right">
|
||||
<q-btn flat label="Cancel" v-close-popup />
|
||||
<q-btn flat label="Submit" color="primary" type="submit" />
|
||||
</q-card-actions>
|
||||
</q-form>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import mixins from "@/mixins/mixins";
|
||||
|
||||
export default {
|
||||
name: "URLActionsForm",
|
||||
mixins: [mixins],
|
||||
props: { action: Object },
|
||||
data() {
|
||||
return {
|
||||
localAction: {
|
||||
name: "",
|
||||
desc: "",
|
||||
pattern: "",
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
title() {
|
||||
return this.editing ? "Edit URL Action" : "Add URL Action";
|
||||
},
|
||||
editing() {
|
||||
return !!this.globalAction;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
submit() {
|
||||
this.$q.loading.show();
|
||||
|
||||
let data = {
|
||||
...this.localAction,
|
||||
};
|
||||
|
||||
if (this.editing) {
|
||||
this.$axios
|
||||
.put(`/core/urlaction/${data.id}/`, data)
|
||||
.then(r => {
|
||||
this.$q.loading.hide();
|
||||
this.onOk();
|
||||
this.notifySuccess("Url Action was edited!");
|
||||
})
|
||||
.catch(e => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
} else {
|
||||
this.$axios
|
||||
.post("/core/urlaction/", data)
|
||||
.then(r => {
|
||||
this.$q.loading.hide();
|
||||
this.onOk();
|
||||
this.notifySuccess("URL Action was added!");
|
||||
})
|
||||
.catch(e => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
}
|
||||
},
|
||||
show() {
|
||||
this.$refs.dialog.show();
|
||||
},
|
||||
hide() {
|
||||
this.$refs.dialog.hide();
|
||||
},
|
||||
onHide() {
|
||||
this.$emit("hide");
|
||||
},
|
||||
onOk() {
|
||||
this.$emit("ok");
|
||||
this.hide();
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// If pk prop is set that means we are editing
|
||||
if (this.action) Object.assign(this.localAction, this.action);
|
||||
},
|
||||
};
|
||||
</script>
|
||||
166
src/components/modals/coresettings/URLActionsTable.vue
Normal file
166
src/components/modals/coresettings/URLActionsTable.vue
Normal file
@@ -0,0 +1,166 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="row">
|
||||
<div class="text-subtitle2">URL Actions</div>
|
||||
<q-space />
|
||||
<q-btn size="sm" color="grey-5" icon="fas fa-plus" text-color="black" label="Add URL Action" @click="addAction" />
|
||||
</div>
|
||||
<hr />
|
||||
<q-table
|
||||
dense
|
||||
:data="actions"
|
||||
:columns="columns"
|
||||
:pagination.sync="pagination"
|
||||
row-key="id"
|
||||
binary-state-sort
|
||||
hide-pagination
|
||||
virtual-scroll
|
||||
:rows-per-page-options="[0]"
|
||||
no-data-label="No URL Actions added yet"
|
||||
>
|
||||
<!-- body slots -->
|
||||
<template v-slot:body="props">
|
||||
<q-tr :props="props" class="cursor-pointer" @dblclick="editAction(props.row)">
|
||||
<!-- context menu -->
|
||||
<q-menu context-menu>
|
||||
<q-list dense style="min-width: 200px">
|
||||
<q-item clickable v-close-popup @click="editAction(props.row)">
|
||||
<q-item-section side>
|
||||
<q-icon name="edit" />
|
||||
</q-item-section>
|
||||
<q-item-section>Edit</q-item-section>
|
||||
</q-item>
|
||||
<q-item clickable v-close-popup @click="deleteAction(props.row)">
|
||||
<q-item-section side>
|
||||
<q-icon name="delete" />
|
||||
</q-item-section>
|
||||
<q-item-section>Delete</q-item-section>
|
||||
</q-item>
|
||||
|
||||
<q-separator></q-separator>
|
||||
|
||||
<q-item clickable v-close-popup>
|
||||
<q-item-section>Close</q-item-section>
|
||||
</q-item>
|
||||
</q-list>
|
||||
</q-menu>
|
||||
<!-- name -->
|
||||
<q-td>
|
||||
{{ props.row.name }}
|
||||
</q-td>
|
||||
<!-- desc -->
|
||||
<q-td>
|
||||
{{ props.row.desc }}
|
||||
</q-td>
|
||||
<!-- pattern -->
|
||||
<q-td>
|
||||
{{ props.row.pattern }}
|
||||
</q-td>
|
||||
</q-tr>
|
||||
</template>
|
||||
</q-table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import URLActionsForm from "@/components/modals/coresettings/URLActionsForm";
|
||||
import mixins from "@/mixins/mixins";
|
||||
|
||||
export default {
|
||||
name: "URLActionTable",
|
||||
mixins: [mixins],
|
||||
data() {
|
||||
return {
|
||||
actions: [],
|
||||
pagination: {
|
||||
rowsPerPage: 0,
|
||||
sortBy: "name",
|
||||
descending: true,
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
name: "name",
|
||||
label: "Name",
|
||||
field: "name",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "desc",
|
||||
label: "Description",
|
||||
field: "desc",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
name: "pattern",
|
||||
label: "Pattern",
|
||||
field: "pattern",
|
||||
align: "left",
|
||||
sortable: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
getURLActions() {
|
||||
this.$q.loading.show();
|
||||
|
||||
this.$axios
|
||||
.get("/core/urlaction/")
|
||||
.then(r => {
|
||||
this.$q.loading.hide();
|
||||
this.actions = r.data;
|
||||
})
|
||||
.catch(e => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
},
|
||||
addAction() {
|
||||
this.$q
|
||||
.dialog({
|
||||
component: URLActionsForm,
|
||||
parent: this,
|
||||
})
|
||||
.onOk(() => {
|
||||
this.getURLActions();
|
||||
});
|
||||
},
|
||||
editAction(action) {
|
||||
this.$q
|
||||
.dialog({
|
||||
component: URLActionsForm,
|
||||
parent: this,
|
||||
action: action,
|
||||
})
|
||||
.onOk(() => {
|
||||
this.getURLActions();
|
||||
});
|
||||
},
|
||||
deleteAction(action) {
|
||||
this.$q
|
||||
.dialog({
|
||||
title: `Delete URL Action: ${action.name}?`,
|
||||
cancel: true,
|
||||
ok: { label: "Delete", color: "negative" },
|
||||
})
|
||||
.onOk(() => {
|
||||
this.$q.loading.show();
|
||||
this.$axios
|
||||
.delete(`/core/urlaction/${action.id}/`)
|
||||
.then(r => {
|
||||
this.getURLActions();
|
||||
this.$q.loading.hide();
|
||||
this.notifySuccess(`URL Action: ${action.name} was deleted!`);
|
||||
})
|
||||
.catch(error => {
|
||||
this.$q.loading.hide();
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getURLActions();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
Reference in New Issue
Block a user