From a484554d012d7ca6317390599da38d079a1d4a4c Mon Sep 17 00:00:00 2001
From: "J.-S. Caux" <J.S.Caux@uva.nl>
Date: Sat, 24 Oct 2020 10:32:33 +0200
Subject: [PATCH] Improve viewing of message threads

---
 .../assets/vue/components/MessageContent.vue  | 37 ++++++++-------
 .../assets/vue/components/MessagesTable.vue   | 45 ++++++++++++-------
 2 files changed, 52 insertions(+), 30 deletions(-)

diff --git a/apimail/static/apimail/assets/vue/components/MessageContent.vue b/apimail/static/apimail/assets/vue/components/MessageContent.vue
index 72e592a4e..78c648514 100644
--- a/apimail/static/apimail/assets/vue/components/MessageContent.vue
+++ b/apimail/static/apimail/assets/vue/components/MessageContent.vue
@@ -221,6 +221,23 @@ export default {
 	}
     },
     methods: {
+	markAsRead () {
+	    if (!this.message.read) {
+		fetch('/mail/api/stored_message/' + this.message.uuid + '/mark_as_read',
+		      {
+			  method: 'PATCH',
+			  headers: {
+			      "X-CSRFToken": csrftoken,
+			  }
+		      }
+		     ).then(function(response) {
+			 if (!response.ok) {
+			     throw new Error('HTTP error, status = ' + response.status);
+			 }
+		     });
+		this.message.read = true
+	    }
+	},
 	tagMessage (message, tag, action) {
 	    fetch('/mail/api/stored_message/' + message.uuid + '/tag',
 		  {
@@ -251,21 +268,11 @@ export default {
 	},
     },
     mounted () {
-	if (!this.message.read) {
-	    fetch('/mail/api/stored_message/' + this.message.uuid + '/mark_as_read',
-		  {
-		      method: 'PATCH',
-		      headers: {
-			  "X-CSRFToken": csrftoken,
-		      }
-		  }
-		 ).then(function(response) {
-		     if (!response.ok) {
-			 throw new Error('HTTP error, status = ' + response.status);
-		     }
-		 });
-	    this.message.read = true
-	}
+	this.markAsRead()
+    },
+    updated () {
+	// needed: mounted is called for leftmost tab in MessagesTable before any data is loaded
+	this.markAsRead()
     }
 }
 </script>
diff --git a/apimail/static/apimail/assets/vue/components/MessagesTable.vue b/apimail/static/apimail/assets/vue/components/MessagesTable.vue
index 31941c2a4..423ce7c20 100644
--- a/apimail/static/apimail/assets/vue/components/MessagesTable.vue
+++ b/apimail/static/apimail/assets/vue/components/MessagesTable.vue
@@ -293,7 +293,7 @@
     </b-card>
     <div v-if="threadOf" class="m-2">
       <b-button size="sm" variant="info"><strong>Focusing on thread</strong></b-button>
-      <b-button size="sm" variant="warning" @click="threadOf = null">
+      <b-button size="sm" variant="warning" @click="unfocusThread()">
 	Unfocus
       </b-button>
     </div>
@@ -317,13 +317,21 @@
       	  <strong>Loading...</strong>
       	</div>
       </template>
+      <template v-slot:head(read)="row">
+	<span v-if="threadOf">
+	  Tab
+	</span>
+      </template>
       <template v-slot:head(tags)="row">
 	Tags
       </template>
       <template v-slot:cell(read)="row">
-	<div v-if="!row.item.read">
+	<span v-if="tabbedMessages.includes(row.item)">
+	  {{ tabbedMessages.length - tabbedMessages.indexOf(row.item) }}
+	</span>
+	<span v-if="!row.item.read">
 	  <b-badge variant="primary">&emsp;</b-badge>
-	</div>
+	</span>
       </template>
       <template v-slot:cell(tags)="row">
 	<ul class="list-inline">
@@ -375,12 +383,15 @@
 	</b-col>
       </b-row>
     </b-card>
-    <b-tabs class="mt-4">
+    <b-tabs
+      class="mt-4"
+      lazy
+      >
       <b-tab
-	v-for="message in tabbedMessages"
+	v-for="(message, index) in tabbedMessages"
 	>
 	<template v-slot:title>
-	  {{ message.data.subject.substr(0,16) }}
+	  {{ tabbedMessages.length - index }}
 	  <b-button size="sm" variant="light" class="float-right ml-2 p-0" @click="closeTab(message.uuid)">
 	    <svg width="1em" height="1em" viewBox="0 0 16 16" class="bi bi-x" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
 	      <path fill-rule="evenodd" d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"/>
@@ -388,14 +399,9 @@
 	  </b-button>
 	  <br>
 	</template>
-	<div v-if="threadOf != message.uuid">
-	  <b-button class="m-2" size="sm" variant="primary" @click="threadOf = message.uuid">
-	    Focus on this thread
-	  </b-button>
-	</div>
-	<div v-else>
-	  <b-button class="m-2" size="sm" variant="warning" @click="threadOf = null">
-	    Unfocus this thread
+	<div v-if="!threadOf">
+	  <b-button class="m-2" size="sm" variant="primary" @click="focusOnThread(message.uuid)">
+	    Focus on this message's thread
 	  </b-button>
 	</div>
 	<message-content
@@ -438,7 +444,6 @@ export default {
 	    draftMessages: [],
 	    draftMessageSelected: null,
 	    queuedMessages: null,
-	    messages: [],
 	    tabbedMessages: [],
 	    perPage: 8,
 	    perPageOptions: [ 8, 16, 32 ],
@@ -579,6 +584,9 @@ export default {
 		.then(data => {
 		    const items = data.results
 		    this.totalRows = data.count
+		    if (this.threadOf) {
+			this.tabbedMessages = items
+		    }
 		    return items || []
 		})
 	},
@@ -598,6 +606,13 @@ export default {
 		this.tabbedMessages.push(item)
 	    }
 	},
+	focusOnThread (uuid) {
+	    this.threadOf = uuid
+	},
+	unfocusThread () {
+	    this.threadOf = null
+	    this.tabbedMessages = []
+	},
 	closeTab(uuid) {
 	    for (let i = 0; i < this.tabbedMessages.length; i++) {
 		if (this.tabbedMessages[i].uuid === uuid) {
-- 
GitLab