feat: add client tree sorting closes #316

This commit is contained in:
wh1te909 2021-03-09 03:17:43 +00:00
parent 196f73705d
commit 8170d5ea73
9 changed files with 95 additions and 37 deletions

View File

@ -0,0 +1,18 @@
# Generated by Django 3.1.7 on 2021-03-09 02:33
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('accounts', '0012_user_agents_per_page'),
]
operations = [
migrations.AddField(
model_name='user',
name='client_tree_sort',
field=models.CharField(choices=[('alphafail', 'Move failing clients to the top'), ('alpha', 'Sort alphabetically')], default='alphafail', max_length=50),
),
]

View File

@ -15,6 +15,11 @@ AGENT_TBL_TAB_CHOICES = [
("mixed", "Mixed"),
]
CLIENT_TREE_SORT_CHOICES = [
("alphafail", "Move failing clients to the top"),
("alpha", "Sort alphabetically"),
]
class User(AbstractUser, BaseAuditModel):
is_active = models.BooleanField(default=True)
@ -27,7 +32,10 @@ class User(AbstractUser, BaseAuditModel):
default_agent_tbl_tab = models.CharField(
max_length=50, choices=AGENT_TBL_TAB_CHOICES, default="server"
)
agents_per_page = models.PositiveIntegerField(default=50)
agents_per_page = models.PositiveIntegerField(default=50) # not currently used
client_tree_sort = models.CharField(
max_length=50, choices=CLIENT_TREE_SORT_CHOICES, default="alphafail"
)
agent = models.OneToOneField(
"agents.Agent",

View File

@ -4,6 +4,18 @@ from rest_framework.serializers import ModelSerializer, SerializerMethodField
from .models import User
class UserUISerializer(ModelSerializer):
class Meta:
model = User
fields = [
"dark_mode",
"show_community_scripts",
"agent_dblclick_action",
"default_agent_tbl_tab",
"client_tree_sort",
]
class UserSerializer(ModelSerializer):
class Meta:
model = User

View File

@ -271,19 +271,13 @@ class TestUserAction(TacticalTestCase):
def test_user_ui(self):
url = "/accounts/users/ui/"
data = {"dark_mode": False}
r = self.client.patch(url, data, format="json")
self.assertEqual(r.status_code, 200)
data = {"show_community_scripts": True}
r = self.client.patch(url, data, format="json")
self.assertEqual(r.status_code, 200)
data = {
"userui": True,
"dark_mode": True,
"show_community_scripts": True,
"agent_dblclick_action": "editagent",
"default_agent_tbl_tab": "mixed",
"agents_per_page": 1000,
"client_tree_sort": "alpha",
}
r = self.client.patch(url, data, format="json")
self.assertEqual(r.status_code, 200)

View File

@ -14,7 +14,7 @@ from logs.models import AuditLog
from tacticalrmm.utils import notify_error
from .models import User
from .serializers import TOTPSetupSerializer, UserSerializer
from .serializers import TOTPSetupSerializer, UserSerializer, UserUISerializer
class CheckCreds(KnoxLoginView):
@ -184,23 +184,9 @@ class TOTPSetup(APIView):
class UserUI(APIView):
def patch(self, request):
user = request.user
if "dark_mode" in request.data.keys():
user.dark_mode = request.data["dark_mode"]
user.save(update_fields=["dark_mode"])
if "show_community_scripts" in request.data.keys():
user.show_community_scripts = request.data["show_community_scripts"]
user.save(update_fields=["show_community_scripts"])
if "userui" in request.data.keys():
user.agent_dblclick_action = request.data["agent_dblclick_action"]
user.default_agent_tbl_tab = request.data["default_agent_tbl_tab"]
user.save(update_fields=["agent_dblclick_action", "default_agent_tbl_tab"])
if "agents_per_page" in request.data.keys():
user.agents_per_page = request.data["agents_per_page"]
user.save(update_fields=["agents_per_page"])
serializer = UserUISerializer(
instance=request.user, data=request.data, partial=True
)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response("ok")

View File

@ -63,7 +63,7 @@ def dashboard_info(request):
"show_community_scripts": request.user.show_community_scripts,
"dbl_click_action": request.user.agent_dblclick_action,
"default_agent_tbl_tab": request.user.default_agent_tbl_tab,
"agents_per_page": request.user.agents_per_page,
"client_tree_sort": request.user.client_tree_sort,
}
)

View File

@ -46,6 +46,20 @@
class="col-4"
/>
</q-card-section>
<q-card-section class="row">
<div class="col-2">Client Sort:</div>
<div class="col-2"></div>
<q-select
map-options
emit-value
outlined
dense
options-dense
v-model="clientTreeSort"
:options="clientTreeSortOptions"
class="col-8"
/>
</q-card-section>
</q-tab-panel>
</q-tab-panels>
@ -68,8 +82,19 @@ export default {
return {
agentDblClickAction: "",
defaultAgentTblTab: "",
clientTreeSort: "",
tab: "ui",
splitterModel: 20,
clientTreeSortOptions: [
{
label: "Sort alphabetically, moving failing clients to the top",
value: "alphafail",
},
{
label: "Sort alphabetically only",
value: "alpha",
},
],
agentDblClickOptions: [
{
label: "Edit Agent",
@ -105,17 +130,19 @@ export default {
this.$axios.get("/core/dashinfo/").then(r => {
this.agentDblClickAction = r.data.dbl_click_action;
this.defaultAgentTblTab = r.data.default_agent_tbl_tab;
this.clientTreeSort = r.data.client_tree_sort;
});
},
editUserPrefs() {
const data = {
userui: true,
agent_dblclick_action: this.agentDblClickAction,
default_agent_tbl_tab: this.defaultAgentTblTab,
client_tree_sort: this.clientTreeSort,
};
this.$axios.patch("/accounts/users/ui/", data).then(r => {
this.notifySuccess("Preferences were saved!");
this.$emit("edited");
this.$store.dispatch("loadTree");
this.$emit("close");
});
},

View File

@ -32,6 +32,7 @@ export default function () {
showCommunityScripts: false,
agentDblClickAction: "",
defaultAgentTblTab: "server",
clientTreeSort: "alphafail",
},
getters: {
loggedIn(state) {
@ -139,6 +140,9 @@ export default function () {
},
SET_DEFAULT_AGENT_TBL_TAB(state, tab) {
state.defaultAgentTblTab = tab
},
SET_CLIENT_TREE_SORT(state, val) {
state.clientTreeSort = val
}
},
actions: {
@ -215,7 +219,7 @@ export default function () {
loadSites(context) {
return axios.get("/clients/sites/");
},
loadTree({ commit }) {
loadTree({ commit, state }) {
axios.get("/clients/tree/").then(r => {
if (r.data.length === 0) {
@ -263,9 +267,15 @@ export default function () {
output.push(clientNode);
}
// move failing clients to the top
const sortedByFailing = output.sort(a => a.color === "negative" ? -1 : 1)
commit("loadTree", sortedByFailing);
if (state.clientTreeSort === "alphafail") {
// move failing clients to the top
const sortedByFailing = output.sort(a => a.color === "negative" ? -1 : 1);
commit("loadTree", sortedByFailing);
} else {
commit("loadTree", output);
}
});
},
checkVer(context) {

View File

@ -712,7 +712,10 @@ export default {
},
getDashInfo(edited = true) {
this.$store.dispatch("getDashInfo").then(r => {
if (edited) this.$store.commit("SET_DEFAULT_AGENT_TBL_TAB", r.data.default_agent_tbl_tab);
if (edited) {
this.$store.commit("SET_DEFAULT_AGENT_TBL_TAB", r.data.default_agent_tbl_tab);
this.$store.commit("SET_CLIENT_TREE_SORT", r.data.client_tree_sort);
}
this.darkMode = r.data.dark_mode;
this.$q.dark.set(this.darkMode);
this.currentTRMMVersion = r.data.trmm_version;