feat: Add email count tracking to folders with total and pending counts

This commit is contained in:
Bryce
2025-08-05 11:04:37 -07:00
parent 31871ed8ec
commit f2fe9d646b
4 changed files with 122 additions and 29 deletions

View File

@@ -130,6 +130,49 @@ class IMAPService:
except:
pass
def get_folder_email_count(self, folder_name: str) -> int:
"""Get the count of emails in a specific folder."""
try:
# Connect to IMAP server
self._connect()
# Login
self.connection.login(
self.config.get('username', ''),
self.config.get('password', '')
)
# Select the folder
resp_code, content = self.connection.select(folder_name)
if resp_code != 'OK':
return 0
# Get email count
resp_code, content = self.connection.search(None, 'ALL')
if resp_code != 'OK':
return 0
# Count the emails
email_ids = content[0].split()
count = len(email_ids)
# Close folder and logout
self.connection.close()
self.connection.logout()
self.connection = None
return count
except Exception as e:
logging.error(f"Error getting email count for folder {folder_name}: {str(e)}")
if self.connection:
try:
self.connection.logout()
except:
pass
self.connection = None
return 0
def sync_folders(self) -> Tuple[bool, str]:
"""Sync IMAP folders with local database."""
try:
@@ -171,6 +214,12 @@ class IMAPService:
)
db.session.add(new_folder)
synced_count += 1
else:
# Update existing folder with email counts
# Get the total count of emails in this folder
total_count = self.get_folder_email_count(folder_name)
existing_folder.total_count = total_count
existing_folder.pending_count = 0 # Initially set to 0
db.session.commit()
return True, f"Successfully synced {synced_count} folders"

View File

@@ -40,5 +40,7 @@ class Folder(Base):
rule_text = db.Column(db.Text)
priority = db.Column(db.Integer)
organize_enabled = db.Column(db.Boolean, default=True)
total_count = db.Column(db.Integer, default=0)
pending_count = db.Column(db.Integer, default=0)
user = db.relationship('User', backref=db.backref('folders', lazy=True))

View File

@@ -1,37 +1,38 @@
<div id="folder-{{ folder.id }}" class="card bg-base-100 shadow-xl border border-base-300 hover:shadow-lg transition-shadow duration-200">
<div class="card-body" data-loading-states>
<div class="flex justify-between items-start mb-2">
<h3 class="text-xl font-bold truncate">{{ folder.name }}</h3>
<h3 class="text-xl font-bold truncate flex-grow">{{ folder.name }}</h3>
<div class="flex space-x-2">
<button class="btn btn-sm btn-outline"
hx-get="/api/folders/{{ folder.id }}/edit"
hx-target="#modal-holder"
hx-swap="innerHTML"
hx-trigger="click"
data-loading-disable
>
<i class="fas fa-edit" data-loading-class="!hidden"></i>
<span class="loading loading-spinner loading-xs hidden" data-loading-class-remove="hidden"></span>
</button>
<button class="btn btn-sm btn-outline btn-error"
hx-delete="/api/folders/{{ folder.id }}"
hx-target="#folders-list"
hx-swap="innerHTML"
hx-confirm="Are you sure you want to delete this folder?"
data-loading-disable
>
<i class="fas fa-trash" data-loading-class="!hidden"></i>
<span class="loading loading-spinner loading-xs hidden" data-loading-class-remove="hidden"></span>
</button>
</div>
</div>
<div class="bg-base-200 rounded-box p-4 mb-4">
<p class="text-base-content/80">{{ folder.rule_text }}</p>
<button class="btn btn-sm btn-outline"
hx-get="/api/folders/{{ folder.id }}/edit"
hx-target="#modal-holder"
hx-swap="innerHTML"
hx-trigger="click"
data-loading-disable
>
<i class="fas fa-edit" data-loading-class="!hidden"></i>
<span class="loading loading-spinner loading-xs hidden" data-loading-class-remove="hidden"></span>
</button>
<button class="btn btn-sm btn-outline btn-error"
hx-delete="/api/folders/{{ folder.id }}"
hx-target="#folders-list"
hx-swap="innerHTML"
hx-confirm="Are you sure you want to delete this folder?"
data-loading-disable
>
<i class="fas fa-trash" data-loading-class="!hidden"></i>
<span class="loading loading-spinner loading-xs hidden" data-loading-class-remove="hidden"></span>
</button>
</div>
</div>
<div class="flex justify-between items-center mt-2">
<!-- Email count badges placed below title but in a separate row -->
<div class="flex justify-between items-center mb-2">
<div class="flex space-x-1">
<span class="badge badge-outline">{{ folder.total_count }} emails</span>
<span class="badge badge-secondary">{{ folder.pending_count }} pending</span>
</div>
{% if folder.priority == 1 %}
<span class="badge badge-error">High Priority</span>
{% elif folder.priority == -1 %}
@@ -39,6 +40,13 @@
{% else %}
<span class="badge badge-primary">Normal Priority</span>
{% endif %}
</div>
<div class="bg-base-200 rounded-box p-4 mb-4">
<p class="text-base-content/80">{{ folder.rule_text }}</p>
</div>
<div class="flex justify-between items-center mt-2">
<div class="flex items-center space-x-2">
<span class="text-xs">Organize:</span>
<input
@@ -52,7 +60,7 @@
data-loading-disable
aria-label="Toggle organize enabled">
</input>
<span class="loading loading-spinner loading-xs hidden" data-loading-class-remove="hidden"></span>
</div>
</div>