-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdashboard_updater.py
More file actions
210 lines (177 loc) Β· 10.5 KB
/
Copy pathdashboard_updater.py
File metadata and controls
210 lines (177 loc) Β· 10.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
"""
Dashboard Updater - Updates Dashboard.md with current system state.
Called after tasks are performed to keep dashboard in sync.
"""
import logging
import re
from datetime import datetime
from pathlib import Path
from typing import Optional
logger = logging.getLogger(__name__)
class DashboardUpdater:
"""Updates Dashboard.md with stats and folder counts."""
def __init__(self, vault_path: Path):
self.vault_path = Path(vault_path)
self.dashboard_path = self.vault_path / "Dashboard.md"
def set_system_online(self) -> None:
"""Set all system components to Online status."""
try:
content = self.dashboard_path.read_text(encoding="utf-8")
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# Update System Status table rows (replace entire row to end of line)
content = re.sub(r"\| Orchestrator \|.*$", "| Orchestrator | π’ Online | - |", content, flags=re.MULTILINE)
content = re.sub(r"\| Gmail Watcher \|.*$", "| Gmail Watcher | π’ Online | - |", content, flags=re.MULTILINE)
content = re.sub(r"\| WhatsApp Watcher \|.*$", "| WhatsApp Watcher | π’ Online | - |", content, flags=re.MULTILINE)
content = re.sub(r"\| LinkedIn Watcher \|.*$", "| LinkedIn Watcher | π’ Online | - |", content, flags=re.MULTILINE)
content = re.sub(r"\| Social Watcher \|.*$", "| Social Watcher | π’ Online | - |", content, flags=re.MULTILINE)
content = re.sub(r"\| Watchdog \|.*$", "| Watchdog | π’ Online | - |", content, flags=re.MULTILINE)
# Update Social Media Posters table rows
content = re.sub(r"\| LinkedIn \|.*$", "| LinkedIn | π’ Online | .linkedin_poster_profile/ |", content, flags=re.MULTILINE)
content = re.sub(r"\| X \(Twitter\) \|.*$", "| X (Twitter) | π’ Online | .x_poster_profile/ |", content, flags=re.MULTILINE)
content = re.sub(r"\| Facebook \|.*$", "| Facebook | π’ Online | .facebook_poster_profile/ |", content, flags=re.MULTILINE)
# Update last updated
content = re.sub(
r"> Last Updated: \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}",
f"> Last Updated: {now}",
content
)
self.dashboard_path.write_text(content, encoding="utf-8")
logger.info("[DashboardUpdater] System set to Online")
except Exception as e:
logger.error(f"[DashboardUpdater] Failed to set system online: {e}")
def set_system_offline(self) -> None:
"""Set all system components to Offline status."""
try:
content = self.dashboard_path.read_text(encoding="utf-8")
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# Update System Status table rows (replace entire row to end of line)
content = re.sub(r"\| Orchestrator \|.*$", "| Orchestrator | π΄ Offline | - |", content, flags=re.MULTILINE)
content = re.sub(r"\| Gmail Watcher \|.*$", "| Gmail Watcher | π΄ Offline | - |", content, flags=re.MULTILINE)
content = re.sub(r"\| WhatsApp Watcher \|.*$", "| WhatsApp Watcher | π΄ Offline | - |", content, flags=re.MULTILINE)
content = re.sub(r"\| LinkedIn Watcher \|.*$", "| LinkedIn Watcher | π΄ Offline | - |", content, flags=re.MULTILINE)
content = re.sub(r"\| Social Watcher \|.*$", "| Social Watcher | π΄ Offline | - |", content, flags=re.MULTILINE)
content = re.sub(r"\| Watchdog \|.*$", "| Watchdog | π΄ Offline | - |", content, flags=re.MULTILINE)
# Update Social Media Posters table rows
content = re.sub(r"\| LinkedIn \|.*$", "| LinkedIn | π΄ Offline | .linkedin_poster_profile/ |", content, flags=re.MULTILINE)
content = re.sub(r"\| X \(Twitter\) \|.*$", "| X (Twitter) | π΄ Offline | .x_poster_profile/ |", content, flags=re.MULTILINE)
content = re.sub(r"\| Facebook \|.*$", "| Facebook | π΄ Offline | .facebook_poster_profile/ |", content, flags=re.MULTILINE)
# Update last updated
content = re.sub(
r"> Last Updated: \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}",
f"> Last Updated: {now}",
content
)
self.dashboard_path.write_text(content, encoding="utf-8")
logger.info("[DashboardUpdater] System set to Offline")
except Exception as e:
logger.error(f"[DashboardUpdater] Failed to set system offline: {e}")
def update_all(self) -> None:
"""Update all dashboard sections except recent activity."""
try:
content = self.dashboard_path.read_text(encoding="utf-8")
# Update folder counts
content = self._update_folder_counts(content)
# Update last updated timestamp
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
content = re.sub(
r"> Last Updated: \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}",
f"> Last Updated: {now}",
content
)
self.dashboard_path.write_text(content, encoding="utf-8")
logger.info("[DashboardUpdater] Dashboard updated")
except Exception as e:
logger.error(f"[DashboardUpdater] Failed to update dashboard: {e}")
def _update_folder_counts(self, content: str) -> str:
"""Update folder counts in Folders Overview."""
folder_mappings = {
# Gmail
"/Gmail/Inbox": "Gmail/Inbox",
"/Gmail/Gmail_Messages/Draft": "Gmail/Gmail_Messages/Draft",
"/Gmail/Gmail_Messages/Done": "Gmail/Gmail_Messages/Done",
# LinkedIn
"/Social_Media/LinkedIn_Posts/Draft": "Social_Media/LinkedIn_Posts/Draft",
"/Social_Media/LinkedIn_Posts/Done": "Social_Media/LinkedIn_Posts/Done",
# X
"/Social_Media/X_Posts/Draft": "Social_Media/X_Posts/Draft",
"/Social_Media/X_Posts/Done": "Social_Media/X_Posts/Done",
# Facebook
"/Social_Media/Facebook_Posts/Draft": "Social_Media/Facebook_Posts/Draft",
"/Social_Media/Facebook_Posts/Done": "Social_Media/Facebook_Posts/Done",
# Odoo Invoices
"/Account/Odoo_Invoices/Draft": "Account/Odoo_Invoices/Draft",
"/Account/Odoo_Invoices/Pending_Payment": "Account/Odoo_Invoices/Pending_Payment",
"/Account/Odoo_Invoices/Done": "Account/Odoo_Invoices/Done",
# Odoo Bills
"/Account/Odoo_Bills/Draft": "Account/Odoo_Bills/Draft",
"/Account/Odoo_Bills/Done": "Account/Odoo_Bills/Done",
}
# Count files in each folder
for display_path, folder_path in folder_mappings.items():
full_path = self.vault_path / folder_path
count = 0
if full_path.exists() and full_path.is_dir():
count = len(list(full_path.glob("*.md")))
# Replace count in table - match literal display_path followed by any number
pattern = rf"\| `{display_path}` \| \d+ \|"
replacement = f"| `{display_path}` | {count} |"
content = re.sub(pattern, replacement, content, flags=re.MULTILINE)
return content
def update_folder(self, folder_name: str) -> None:
"""Update a specific folder's count after file changes."""
try:
content = self.dashboard_path.read_text(encoding="utf-8")
# Find the folder entry and update count
folder_path_map = {
# Gmail
"gmail_inbox": ("/Gmail/Inbox", "Gmail/Inbox"),
"gmail_draft": ("/Gmail/Gmail_Messages/Draft", "Gmail/Gmail_Messages/Draft"),
"gmail_done": ("/Gmail/Gmail_Messages/Done", "Gmail/Gmail_Messages/Done"),
# LinkedIn
"linkedin_draft": ("/Social_Media/LinkedIn_Posts/Draft", "Social_Media/LinkedIn_Posts/Draft"),
"linkedin_done": ("/Social_Media/LinkedIn_Posts/Done", "Social_Media/LinkedIn_Posts/Done"),
# X
"x_draft": ("/Social_Media/X_Posts/Draft", "Social_Media/X_Posts/Draft"),
"x_done": ("/Social_Media/X_Posts/Done", "Social_Media/X_Posts/Done"),
# Facebook
"facebook_draft": ("/Social_Media/Facebook_Posts/Draft", "Social_Media/Facebook_Posts/Draft"),
"facebook_done": ("/Social_Media/Facebook_Posts/Done", "Social_Media/Facebook_Posts/Done"),
# Odoo Invoices
"odoo_invoices_draft": ("/Account/Odoo_Invoices/Draft", "Account/Odoo_Invoices/Draft"),
"odoo_invoices_pending_payment": ("/Account/Odoo_Invoices/Pending_Payment", "Account/Odoo_Invoices/Pending_Payment"),
"odoo_invoices_done": ("/Account/Odoo_Invoices/Done", "Account/Odoo_Invoices/Done"),
# Odoo Bills
"odoo_bills_draft": ("/Account/Odoo_Bills/Draft", "Account/Odoo_Bills/Draft"),
"odoo_bills_done": ("/Account/Odoo_Bills/Done", "Account/Odoo_Bills/Done"),
}
if folder_name in folder_path_map:
display_path, actual_path = folder_path_map[folder_name]
full_path = self.vault_path / actual_path
count = 0
if full_path.exists() and full_path.is_dir():
count = len(list(full_path.glob("*.md")))
# Replace count - use regex to match any number
pattern = rf"\| `\{re.escape(display_path)}` \| \d+ \|"
replacement = f"| `{display_path}` | {count} |"
content = re.sub(pattern, replacement, content)
# Also refresh date
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
content = re.sub(
r"> Last Updated: \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}",
f"> Last Updated: {now}",
content
)
self.dashboard_path.write_text(content, encoding="utf-8")
logger.info(f"[DashboardUpdater] Updated folder: {folder_name}")
except Exception as e:
logger.error(f"[DashboardUpdater] Failed to update folder {folder_name}: {e}")
async def update_dashboard_on_action(vault_path: Path, action: str, folder: str = None) -> None:
"""
Convenience function to update dashboard after an action.
Args:
vault_path: Path to AI_Employee_Vault
action: The action performed (e.g., "draft_created", "approved", "posted", "failed")
folder: Specific folder that changed (ignored - always full update)
"""
updater = DashboardUpdater(vault_path)
updater.update_all()