Compare commits
	
		
			12 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 0da1950427 | ||
|  | e590b921be | ||
|  | 09462692f5 | ||
|  | c1d1b5f762 | ||
|  | 6b9c87b858 | ||
|  | 485b6eb904 | ||
|  | 057630bdb5 | ||
|  | 6b02873b30 | ||
|  | 0fa0fc6d6b | ||
|  | 339ec07465 | ||
|  | cd2e798fea | ||
|  | d5cadbeae2 | 
| @@ -0,0 +1,26 @@ | |||||||
|  | # Generated by Django 3.1.5 on 2021-01-18 09:40 | ||||||
|  |  | ||||||
|  | from django.db import migrations, models | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class Migration(migrations.Migration): | ||||||
|  |  | ||||||
|  |     dependencies = [ | ||||||
|  |         ("accounts", "0010_user_agent_dblclick_action"), | ||||||
|  |     ] | ||||||
|  |  | ||||||
|  |     operations = [ | ||||||
|  |         migrations.AddField( | ||||||
|  |             model_name="user", | ||||||
|  |             name="default_agent_tbl_tab", | ||||||
|  |             field=models.CharField( | ||||||
|  |                 choices=[ | ||||||
|  |                     ("server", "Servers"), | ||||||
|  |                     ("workstation", "Workstations"), | ||||||
|  |                     ("mixed", "Mixed"), | ||||||
|  |                 ], | ||||||
|  |                 default="server", | ||||||
|  |                 max_length=50, | ||||||
|  |             ), | ||||||
|  |         ), | ||||||
|  |     ] | ||||||
| @@ -9,6 +9,12 @@ AGENT_DBLCLICK_CHOICES = [ | |||||||
|     ("remotebg", "Remote Background"), |     ("remotebg", "Remote Background"), | ||||||
| ] | ] | ||||||
|  |  | ||||||
|  | AGENT_TBL_TAB_CHOICES = [ | ||||||
|  |     ("server", "Servers"), | ||||||
|  |     ("workstation", "Workstations"), | ||||||
|  |     ("mixed", "Mixed"), | ||||||
|  | ] | ||||||
|  |  | ||||||
|  |  | ||||||
| class User(AbstractUser, BaseAuditModel): | class User(AbstractUser, BaseAuditModel): | ||||||
|     is_active = models.BooleanField(default=True) |     is_active = models.BooleanField(default=True) | ||||||
| @@ -18,6 +24,9 @@ class User(AbstractUser, BaseAuditModel): | |||||||
|     agent_dblclick_action = models.CharField( |     agent_dblclick_action = models.CharField( | ||||||
|         max_length=50, choices=AGENT_DBLCLICK_CHOICES, default="editagent" |         max_length=50, choices=AGENT_DBLCLICK_CHOICES, default="editagent" | ||||||
|     ) |     ) | ||||||
|  |     default_agent_tbl_tab = models.CharField( | ||||||
|  |         max_length=50, choices=AGENT_TBL_TAB_CHOICES, default="server" | ||||||
|  |     ) | ||||||
|  |  | ||||||
|     agent = models.OneToOneField( |     agent = models.OneToOneField( | ||||||
|         "agents.Agent", |         "agents.Agent", | ||||||
|   | |||||||
| @@ -189,16 +189,17 @@ class UserUI(APIView): | |||||||
|     def patch(self, request): |     def patch(self, request): | ||||||
|         user = request.user |         user = request.user | ||||||
|  |  | ||||||
|         if "dark_mode" in request.data: |         if "dark_mode" in request.data.keys(): | ||||||
|             user.dark_mode = request.data["dark_mode"] |             user.dark_mode = request.data["dark_mode"] | ||||||
|             user.save(update_fields=["dark_mode"]) |             user.save(update_fields=["dark_mode"]) | ||||||
|  |  | ||||||
|         if "show_community_scripts" in request.data: |         if "show_community_scripts" in request.data.keys(): | ||||||
|             user.show_community_scripts = request.data["show_community_scripts"] |             user.show_community_scripts = request.data["show_community_scripts"] | ||||||
|             user.save(update_fields=["show_community_scripts"]) |             user.save(update_fields=["show_community_scripts"]) | ||||||
|  |  | ||||||
|         if "agent_dblclick_action" in request.data: |         if "userui" in request.data.keys(): | ||||||
|             user.agent_dblclick_action = request.data["agent_dblclick_action"] |             user.agent_dblclick_action = request.data["agent_dblclick_action"] | ||||||
|             user.save(update_fields=["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"]) | ||||||
|  |  | ||||||
|         return Response("ok") |         return Response("ok") | ||||||
|   | |||||||
| @@ -42,11 +42,13 @@ class AgentTableSerializer(serializers.ModelSerializer): | |||||||
|     last_seen = serializers.SerializerMethodField() |     last_seen = serializers.SerializerMethodField() | ||||||
|     client_name = serializers.ReadOnlyField(source="client.name") |     client_name = serializers.ReadOnlyField(source="client.name") | ||||||
|     site_name = serializers.ReadOnlyField(source="site.name") |     site_name = serializers.ReadOnlyField(source="site.name") | ||||||
|  |     logged_username = serializers.SerializerMethodField() | ||||||
|  |     italic = serializers.SerializerMethodField() | ||||||
|  |  | ||||||
|     def get_pending_actions(self, obj): |     def get_pending_actions(self, obj): | ||||||
|         return obj.pendingactions.filter(status="pending").count() |         return obj.pendingactions.filter(status="pending").count() | ||||||
|  |  | ||||||
|     def get_last_seen(self, obj): |     def get_last_seen(self, obj) -> str: | ||||||
|         if obj.time_zone is not None: |         if obj.time_zone is not None: | ||||||
|             agent_tz = pytz.timezone(obj.time_zone) |             agent_tz = pytz.timezone(obj.time_zone) | ||||||
|         else: |         else: | ||||||
| @@ -54,6 +56,17 @@ class AgentTableSerializer(serializers.ModelSerializer): | |||||||
|  |  | ||||||
|         return obj.last_seen.astimezone(agent_tz).strftime("%m %d %Y %H:%M:%S") |         return obj.last_seen.astimezone(agent_tz).strftime("%m %d %Y %H:%M:%S") | ||||||
|  |  | ||||||
|  |     def get_logged_username(self, obj) -> str: | ||||||
|  |         if obj.logged_in_username == "None" and obj.status == "online": | ||||||
|  |             return obj.last_logged_in_user | ||||||
|  |         elif obj.logged_in_username != "None": | ||||||
|  |             return obj.logged_in_username | ||||||
|  |         else: | ||||||
|  |             return "-" | ||||||
|  |  | ||||||
|  |     def get_italic(self, obj) -> bool: | ||||||
|  |         return obj.logged_in_username == "None" and obj.status == "online" | ||||||
|  |  | ||||||
|     class Meta: |     class Meta: | ||||||
|         model = Agent |         model = Agent | ||||||
|         fields = [ |         fields = [ | ||||||
| @@ -73,9 +86,9 @@ class AgentTableSerializer(serializers.ModelSerializer): | |||||||
|             "last_seen", |             "last_seen", | ||||||
|             "boot_time", |             "boot_time", | ||||||
|             "checks", |             "checks", | ||||||
|             "logged_in_username", |  | ||||||
|             "last_logged_in_user", |  | ||||||
|             "maintenance_mode", |             "maintenance_mode", | ||||||
|  |             "logged_username", | ||||||
|  |             "italic", | ||||||
|         ] |         ] | ||||||
|         depth = 2 |         depth = 2 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -111,9 +111,12 @@ def send_agent_update_task(pks: List[int], version: str) -> None: | |||||||
|     agents: List[int] = [ |     agents: List[int] = [ | ||||||
|         i.pk for i in q if pyver.parse(i.version) < pyver.parse(version) |         i.pk for i in q if pyver.parse(i.version) < pyver.parse(version) | ||||||
|     ] |     ] | ||||||
|  |     chunks = (agents[i : i + 30] for i in range(0, len(agents), 30)) | ||||||
|     for pk in agents: |     for chunk in chunks: | ||||||
|         agent_update(pk) |         for pk in chunk: | ||||||
|  |             agent_update(pk) | ||||||
|  |             sleep(0.05) | ||||||
|  |         sleep(4) | ||||||
|  |  | ||||||
|  |  | ||||||
| @app.task | @app.task | ||||||
| @@ -129,8 +132,12 @@ def auto_self_agent_update_task() -> None: | |||||||
|         if pyver.parse(i.version) < pyver.parse(settings.LATEST_AGENT_VER) |         if pyver.parse(i.version) < pyver.parse(settings.LATEST_AGENT_VER) | ||||||
|     ] |     ] | ||||||
|  |  | ||||||
|     for pk in pks: |     chunks = (pks[i : i + 30] for i in range(0, len(pks), 30)) | ||||||
|         agent_update(pk) |     for chunk in chunks: | ||||||
|  |         for pk in chunk: | ||||||
|  |             agent_update(pk) | ||||||
|  |             sleep(0.05) | ||||||
|  |         sleep(4) | ||||||
|  |  | ||||||
|  |  | ||||||
| @app.task | @app.task | ||||||
|   | |||||||
| @@ -72,6 +72,7 @@ def dashboard_info(request): | |||||||
|             "dark_mode": request.user.dark_mode, |             "dark_mode": request.user.dark_mode, | ||||||
|             "show_community_scripts": request.user.show_community_scripts, |             "show_community_scripts": request.user.show_community_scripts, | ||||||
|             "dbl_click_action": request.user.agent_dblclick_action, |             "dbl_click_action": request.user.agent_dblclick_action, | ||||||
|  |             "default_agent_tbl_tab": request.user.default_agent_tbl_tab, | ||||||
|         } |         } | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|   | |||||||
| @@ -15,17 +15,17 @@ EXE_DIR = os.path.join(BASE_DIR, "tacticalrmm/private/exe") | |||||||
| AUTH_USER_MODEL = "accounts.User" | AUTH_USER_MODEL = "accounts.User" | ||||||
|  |  | ||||||
| # latest release | # latest release | ||||||
| TRMM_VERSION = "0.3.0" | TRMM_VERSION = "0.3.3" | ||||||
|  |  | ||||||
| # bump this version everytime vue code is changed | # bump this version everytime vue code is changed | ||||||
| # to alert user they need to manually refresh their browser | # to alert user they need to manually refresh their browser | ||||||
| APP_VER = "0.0.104" | APP_VER = "0.0.106" | ||||||
|  |  | ||||||
| # https://github.com/wh1te909/salt | # https://github.com/wh1te909/salt | ||||||
| LATEST_SALT_VER = "1.1.0" | LATEST_SALT_VER = "1.1.0" | ||||||
|  |  | ||||||
| # https://github.com/wh1te909/rmmagent | # https://github.com/wh1te909/rmmagent | ||||||
| LATEST_AGENT_VER = "1.2.0" | LATEST_AGENT_VER = "1.2.1" | ||||||
|  |  | ||||||
| MESH_VER = "0.7.45" | MESH_VER = "0.7.45" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -139,7 +139,7 @@ server { | |||||||
| } | } | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| 4. Edit `/meshcentral/meshcentral-data/config.json` and change to match the example below. Replace `mesh.example.com` with your mesh domain. | 4. Edit `/meshcentral/meshcentral-data/config.json` and change to match the example below. Replace `mesh.example.com` with your mesh domain. After editing, use a json linter like `https://jsonlint.com/` to verify no syntax errors, otherwise meshcentral will fail to start. | ||||||
| ``` | ``` | ||||||
| { | { | ||||||
|   "settings": { |   "settings": { | ||||||
|   | |||||||
| @@ -53,12 +53,6 @@ | |||||||
|           </q-icon> |           </q-icon> | ||||||
|         </q-th> |         </q-th> | ||||||
|       </template> |       </template> | ||||||
|       <!-- |  | ||||||
|       <template v-slot:header-cell-antivirus="props"> |  | ||||||
|         <q-th auto-width :props="props"> |  | ||||||
|           <q-icon name="fas fa-shield-alt" size="1.2em" color="primary"><q-tooltip>Anti Virus</q-tooltip></q-icon> |  | ||||||
|         </q-th> |  | ||||||
|       </template>--> |  | ||||||
|       <template v-slot:header-cell-agentstatus="props"> |       <template v-slot:header-cell-agentstatus="props"> | ||||||
|         <q-th auto-width :props="props"> |         <q-th auto-width :props="props"> | ||||||
|           <q-icon name="fas fa-signal" size="1.2em"> |           <q-icon name="fas fa-signal" size="1.2em"> | ||||||
| @@ -286,11 +280,8 @@ | |||||||
|           <q-td key="hostname" :props="props">{{ props.row.hostname }}</q-td> |           <q-td key="hostname" :props="props">{{ props.row.hostname }}</q-td> | ||||||
|           <q-td key="description" :props="props">{{ props.row.description }}</q-td> |           <q-td key="description" :props="props">{{ props.row.description }}</q-td> | ||||||
|           <q-td key="user" :props="props"> |           <q-td key="user" :props="props"> | ||||||
|             <span class="text-italic" v-if="props.row.logged_in_username === 'None' && props.row.status === 'online'">{{ |             <span class="text-italic" v-if="props.row.italic">{{ props.row.logged_username }}</span> | ||||||
|               props.row.last_logged_in_user |             <span v-else>{{ props.row.logged_username }}</span> | ||||||
|             }}</span> |  | ||||||
|             <span v-else-if="props.row.logged_in_username !== 'None'">{{ props.row.logged_in_username }}</span> |  | ||||||
|             <span v-else>-</span> |  | ||||||
|           </q-td> |           </q-td> | ||||||
|           <q-td :props="props" key="patchespending"> |           <q-td :props="props" key="patchespending"> | ||||||
|             <q-icon v-if="props.row.patches_pending" name="far fa-clock" color="primary"> |             <q-icon v-if="props.row.patches_pending" name="far fa-clock" color="primary"> | ||||||
| @@ -455,10 +446,6 @@ export default { | |||||||
|           } |           } | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // fix for last_logged_in_user not filtering |  | ||||||
|         if (row.logged_in_username === "None" && row.status === "online" && !!row.last_logged_in_user) |  | ||||||
|           return row.last_logged_in_user.toLowerCase().indexOf(search) !== -1; |  | ||||||
|  |  | ||||||
|         // Normal text filter |         // Normal text filter | ||||||
|         return cols.some(col => { |         return cols.some(col => { | ||||||
|           const val = cellValue(col, row) + ""; |           const val = cellValue(col, row) + ""; | ||||||
|   | |||||||
| @@ -32,6 +32,20 @@ | |||||||
|                   class="col-4" |                   class="col-4" | ||||||
|                 /> |                 /> | ||||||
|               </q-card-section> |               </q-card-section> | ||||||
|  |               <q-card-section class="row"> | ||||||
|  |                 <div class="col-6">Agent table default tab:</div> | ||||||
|  |                 <div class="col-2"></div> | ||||||
|  |                 <q-select | ||||||
|  |                   map-options | ||||||
|  |                   emit-value | ||||||
|  |                   outlined | ||||||
|  |                   dense | ||||||
|  |                   options-dense | ||||||
|  |                   v-model="defaultAgentTblTab" | ||||||
|  |                   :options="defaultAgentTblTabOptions" | ||||||
|  |                   class="col-4" | ||||||
|  |                 /> | ||||||
|  |               </q-card-section> | ||||||
|             </q-tab-panel> |             </q-tab-panel> | ||||||
|           </q-tab-panels> |           </q-tab-panels> | ||||||
|  |  | ||||||
| @@ -54,6 +68,7 @@ export default { | |||||||
|   data() { |   data() { | ||||||
|     return { |     return { | ||||||
|       agentDblClickAction: "", |       agentDblClickAction: "", | ||||||
|  |       defaultAgentTblTab: "", | ||||||
|       tab: "ui", |       tab: "ui", | ||||||
|       splitterModel: 20, |       splitterModel: 20, | ||||||
|       agentDblClickOptions: [ |       agentDblClickOptions: [ | ||||||
| @@ -70,16 +85,35 @@ export default { | |||||||
|           value: "remotebg", |           value: "remotebg", | ||||||
|         }, |         }, | ||||||
|       ], |       ], | ||||||
|  |       defaultAgentTblTabOptions: [ | ||||||
|  |         { | ||||||
|  |           label: "Servers", | ||||||
|  |           value: "server", | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           label: "Workstations", | ||||||
|  |           value: "workstation", | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           label: "Mixed", | ||||||
|  |           value: "mixed", | ||||||
|  |         }, | ||||||
|  |       ], | ||||||
|     }; |     }; | ||||||
|   }, |   }, | ||||||
|   methods: { |   methods: { | ||||||
|     getUserPrefs() { |     getUserPrefs() { | ||||||
|       this.$axios.get("/core/dashinfo/").then(r => { |       this.$axios.get("/core/dashinfo/").then(r => { | ||||||
|         this.agentDblClickAction = r.data.dbl_click_action; |         this.agentDblClickAction = r.data.dbl_click_action; | ||||||
|  |         this.defaultAgentTblTab = r.data.default_agent_tbl_tab; | ||||||
|       }); |       }); | ||||||
|     }, |     }, | ||||||
|     editUserPrefs() { |     editUserPrefs() { | ||||||
|       const data = { agent_dblclick_action: this.agentDblClickAction }; |       const data = { | ||||||
|  |         userui: true, | ||||||
|  |         agent_dblclick_action: this.agentDblClickAction, | ||||||
|  |         default_agent_tbl_tab: this.defaultAgentTblTab, | ||||||
|  |       }; | ||||||
|       this.$axios.patch("/accounts/users/ui/", data).then(r => { |       this.$axios.patch("/accounts/users/ui/", data).then(r => { | ||||||
|         this.notifySuccess("Preferences were saved!"); |         this.notifySuccess("Preferences were saved!"); | ||||||
|         this.$emit("edited"); |         this.$emit("edited"); | ||||||
|   | |||||||
| @@ -35,6 +35,7 @@ export default function () { | |||||||
|       tabHeight: "35vh", |       tabHeight: "35vh", | ||||||
|       showCommunityScripts: false, |       showCommunityScripts: false, | ||||||
|       agentDblClickAction: "", |       agentDblClickAction: "", | ||||||
|  |       defaultAgentTblTab: "server", | ||||||
|     }, |     }, | ||||||
|     getters: { |     getters: { | ||||||
|       loggedIn(state) { |       loggedIn(state) { | ||||||
| @@ -139,6 +140,9 @@ export default function () { | |||||||
|       }, |       }, | ||||||
|       SET_AGENT_DBLCLICK_ACTION(state, action) { |       SET_AGENT_DBLCLICK_ACTION(state, action) { | ||||||
|         state.agentDblClickAction = action |         state.agentDblClickAction = action | ||||||
|  |       }, | ||||||
|  |       SET_DEFAULT_AGENT_TBL_TABd(state, tab) { | ||||||
|  |         state.defaultAgentTblTab = tab | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     actions: { |     actions: { | ||||||
|   | |||||||
| @@ -195,7 +195,6 @@ | |||||||
|                 </q-tabs> |                 </q-tabs> | ||||||
|                 <q-space /> |                 <q-space /> | ||||||
|                 <q-input |                 <q-input | ||||||
|                   autogrow |  | ||||||
|                   v-model="search" |                   v-model="search" | ||||||
|                   style="width: 450px" |                   style="width: 450px" | ||||||
|                   label="Search" |                   label="Search" | ||||||
| @@ -411,7 +410,6 @@ export default { | |||||||
|       outsideModel: 11, |       outsideModel: 11, | ||||||
|       selectedTree: "", |       selectedTree: "", | ||||||
|       innerModel: 50, |       innerModel: 50, | ||||||
|       tab: "server", |  | ||||||
|       clientActive: "", |       clientActive: "", | ||||||
|       siteActive: "", |       siteActive: "", | ||||||
|       frame: [], |       frame: [], | ||||||
| @@ -472,16 +470,13 @@ export default { | |||||||
|         { |         { | ||||||
|           name: "user", |           name: "user", | ||||||
|           label: "User", |           label: "User", | ||||||
|           field: "logged_in_username", |           field: "logged_username", | ||||||
|           sortable: true, |           sortable: true, | ||||||
|           align: "left", |           align: "left", | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|           name: "lastuser", |           name: "italic", | ||||||
|           label: "Last User", |           field: "italic", | ||||||
|           field: "last_logged_in_user", |  | ||||||
|           sortable: true, |  | ||||||
|           align: "left", |  | ||||||
|         }, |         }, | ||||||
|         { |         { | ||||||
|           name: "patchespending", |           name: "patchespending", | ||||||
| @@ -686,6 +681,7 @@ export default { | |||||||
|         this.$q.dark.set(this.darkMode); |         this.$q.dark.set(this.darkMode); | ||||||
|         this.currentTRMMVersion = r.data.trmm_version; |         this.currentTRMMVersion = r.data.trmm_version; | ||||||
|         this.$store.commit("SET_AGENT_DBLCLICK_ACTION", r.data.dbl_click_action); |         this.$store.commit("SET_AGENT_DBLCLICK_ACTION", r.data.dbl_click_action); | ||||||
|  |         this.$store.commit("SET_DEFAULT_AGENT_TBL_TABd", r.data.default_agent_tbl_tab); | ||||||
|         this.$store.commit("setShowCommunityScripts", r.data.show_community_scripts); |         this.$store.commit("setShowCommunityScripts", r.data.show_community_scripts); | ||||||
|       }); |       }); | ||||||
|     }, |     }, | ||||||
| @@ -770,6 +766,14 @@ export default { | |||||||
|       clients: state => state.clients, |       clients: state => state.clients, | ||||||
|     }), |     }), | ||||||
|     ...mapGetters(["selectedAgentPk", "needRefresh"]), |     ...mapGetters(["selectedAgentPk", "needRefresh"]), | ||||||
|  |     tab: { | ||||||
|  |       get: function () { | ||||||
|  |         return this.$store.state.defaultAgentTblTab; | ||||||
|  |       }, | ||||||
|  |       set: function (newVal) { | ||||||
|  |         this.$store.commit("SET_DEFAULT_AGENT_TBL_TABd", newVal); | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|     allClientsActive() { |     allClientsActive() { | ||||||
|       return this.selectedTree === "" ? true : false; |       return this.selectedTree === "" ? true : false; | ||||||
|     }, |     }, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user