Update ashboard, dashboard (~3)
This commit is contained in:
@@ -28,9 +28,43 @@ class TaskBoardHandler(SimpleHTTPRequestHandler):
|
|||||||
self.handle_files_post()
|
self.handle_files_post()
|
||||||
elif self.path == '/api/refresh-index':
|
elif self.path == '/api/refresh-index':
|
||||||
self.handle_refresh_index()
|
self.handle_refresh_index()
|
||||||
|
elif self.path == '/api/git-commit':
|
||||||
|
self.handle_git_commit()
|
||||||
else:
|
else:
|
||||||
self.send_error(404)
|
self.send_error(404)
|
||||||
|
|
||||||
|
def handle_git_commit(self):
|
||||||
|
"""Run git commit and push."""
|
||||||
|
try:
|
||||||
|
script = TOOLS_DIR / 'git_commit.py'
|
||||||
|
result = subprocess.run(
|
||||||
|
[sys.executable, str(script), '--push'],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
timeout=60,
|
||||||
|
cwd=str(BASE_DIR)
|
||||||
|
)
|
||||||
|
|
||||||
|
output = result.stdout + result.stderr
|
||||||
|
|
||||||
|
# Parse files count
|
||||||
|
files_match = re.search(r'Files changed: (\d+)', output)
|
||||||
|
files = int(files_match.group(1)) if files_match else 0
|
||||||
|
|
||||||
|
if result.returncode == 0 or 'Pushing...' in output:
|
||||||
|
self.send_json({
|
||||||
|
'success': True,
|
||||||
|
'files': files,
|
||||||
|
'output': output
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
self.send_json({
|
||||||
|
'success': False,
|
||||||
|
'error': output or 'Unknown error'
|
||||||
|
})
|
||||||
|
except Exception as e:
|
||||||
|
self.send_json({'success': False, 'error': str(e)}, 500)
|
||||||
|
|
||||||
def handle_refresh_index(self):
|
def handle_refresh_index(self):
|
||||||
"""Regenerate memory/kb/index.json"""
|
"""Regenerate memory/kb/index.json"""
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -725,12 +725,13 @@
|
|||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
gap: 12px;
|
gap: 12px;
|
||||||
padding: 10px 12px;
|
padding: 10px 12px;
|
||||||
background: #1f2937;
|
background: #111827;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
|
border: 1px solid #1f2937;
|
||||||
}
|
}
|
||||||
.todo-item:hover { background: #374151; }
|
.todo-item:hover { background: #1f2937; }
|
||||||
.todo-item.done { opacity: 0.6; }
|
.todo-item.done { opacity: 0.6; }
|
||||||
.todo-item.done .todo-text { text-decoration: line-through; }
|
.todo-item.done .todo-text { text-decoration: line-through; }
|
||||||
.todo-checkbox {
|
.todo-checkbox {
|
||||||
@@ -754,6 +755,7 @@
|
|||||||
.todo-checkbox.checked svg { display: block; }
|
.todo-checkbox.checked svg { display: block; }
|
||||||
.todo-content { flex: 1; min-width: 0; }
|
.todo-content { flex: 1; min-width: 0; }
|
||||||
.todo-text { font-size: 14px; color: #f3f4f6; margin-bottom: 4px; }
|
.todo-text { font-size: 14px; color: #f3f4f6; margin-bottom: 4px; }
|
||||||
|
.todo-context { font-size: 13px; color: #9ca3af; margin-bottom: 6px; font-style: italic; }
|
||||||
.todo-meta { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
|
.todo-meta { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
|
||||||
.todo-domain {
|
.todo-domain {
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
@@ -771,6 +773,26 @@
|
|||||||
}
|
}
|
||||||
.todo-due.overdue { color: #ef4444; font-weight: 500; }
|
.todo-due.overdue { color: #ef4444; font-weight: 500; }
|
||||||
.todo-source { font-size: 11px; color: #6b7280; }
|
.todo-source { font-size: 11px; color: #6b7280; }
|
||||||
|
|
||||||
|
/* Button icon only */
|
||||||
|
.btn-icon {
|
||||||
|
padding: 6px;
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid #374151;
|
||||||
|
border-radius: 6px;
|
||||||
|
color: #9ca3af;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
.btn-icon:hover {
|
||||||
|
background: #374151;
|
||||||
|
color: #f3f4f6;
|
||||||
|
border-color: #4b5563;
|
||||||
|
}
|
||||||
|
.btn-icon svg { width: 16px; height: 16px; }
|
||||||
.issue-owner.clawdbot { color: #8b5cf6; }
|
.issue-owner.clawdbot { color: #8b5cf6; }
|
||||||
|
|
||||||
.issue-date {
|
.issue-date {
|
||||||
@@ -931,7 +953,6 @@
|
|||||||
<main class="main">
|
<main class="main">
|
||||||
<div class="page-header">
|
<div class="page-header">
|
||||||
<h1 class="page-title">Dashboard</h1>
|
<h1 class="page-title">Dashboard</h1>
|
||||||
<p class="page-subtitle">Echo Work · Productivitate și proiecte</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Status Bar -->
|
<!-- Status Bar -->
|
||||||
@@ -943,7 +964,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="status-summary" id="statusSummary">Se încarcă...</div>
|
<div class="status-summary" id="statusSummary">Se încarcă...</div>
|
||||||
<div class="status-actions" onclick="event.stopPropagation()">
|
<div class="status-actions" onclick="event.stopPropagation()">
|
||||||
<button class="btn btn-secondary btn-sm" onclick="refreshStatus()" title="Refresh">
|
<button class="btn btn-icon" onclick="gitCommit()" title="Git Commit">
|
||||||
|
<i data-lucide="git-commit"></i>
|
||||||
|
</button>
|
||||||
|
<button class="btn btn-icon" onclick="refreshStatus()" title="Refresh">
|
||||||
<i data-lucide="refresh-cw"></i>
|
<i data-lucide="refresh-cw"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -1017,24 +1041,29 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="dashboard-grid">
|
<div class="dashboard-grid">
|
||||||
<!-- Activity Panel -->
|
<!-- Issues Panel -->
|
||||||
<div class="panel activity-panel" id="activityPanel">
|
<div class="panel issues-panel" id="issuesPanel">
|
||||||
<div class="panel-header" onclick="toggleSection('activityPanel')">
|
<div class="panel-header" onclick="toggleSection('issuesPanel')">
|
||||||
<div class="panel-header-left">
|
<div class="panel-header-left">
|
||||||
<i data-lucide="chevron-down" class="panel-toggle"></i>
|
<i data-lucide="chevron-down" class="panel-toggle"></i>
|
||||||
<div class="panel-title">
|
<div class="panel-title">
|
||||||
<i data-lucide="bot"></i>
|
<span>Issues</span>
|
||||||
<span>Activity</span>
|
|
||||||
</div>
|
</div>
|
||||||
<span class="panel-count" id="activityCount">0</span>
|
<span class="panel-count" id="issuesCount">0</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-actions" onclick="event.stopPropagation()">
|
<div class="panel-actions" onclick="event.stopPropagation()">
|
||||||
<button class="btn btn-secondary btn-sm" onclick="refreshActivity()" title="Refresh">
|
<button class="btn btn-icon" onclick="showAddModal()" title="Adaugă issue">
|
||||||
<i data-lucide="refresh-cw"></i>
|
<i data-lucide="plus"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body" id="activityBody">
|
<div class="issues-filters" id="issuesFilters">
|
||||||
|
<button class="filter-btn active" data-filter="all">Toate</button>
|
||||||
|
<button class="filter-btn" data-filter="marius">👤 Marius</button>
|
||||||
|
<button class="filter-btn" data-filter="robert">👷 Robert</button>
|
||||||
|
<button class="filter-btn" data-filter="clawdbot">🤖 Clawdbot</button>
|
||||||
|
</div>
|
||||||
|
<div class="panel-body" id="issuesBody">
|
||||||
<div class="empty-state">
|
<div class="empty-state">
|
||||||
<i data-lucide="loader"></i>
|
<i data-lucide="loader"></i>
|
||||||
<p>Se încarcă...</p>
|
<p>Se încarcă...</p>
|
||||||
@@ -1042,22 +1071,19 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Issues Panel -->
|
|
||||||
<!-- Todo's Panel -->
|
<!-- Todo's Panel -->
|
||||||
<div class="panel todos-panel" id="todosPanel">
|
<div class="panel todos-panel" id="todosPanel">
|
||||||
<div class="panel-header" onclick="toggleSection('todosPanel')">
|
<div class="panel-header" onclick="toggleSection('todosPanel')">
|
||||||
<div class="panel-header-left">
|
<div class="panel-header-left">
|
||||||
<i data-lucide="chevron-down" class="panel-toggle"></i>
|
<i data-lucide="chevron-down" class="panel-toggle"></i>
|
||||||
<div class="panel-title">
|
<div class="panel-title">
|
||||||
<i data-lucide="list-todo"></i>
|
|
||||||
<span>Todo's</span>
|
<span>Todo's</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="panel-count" id="todosCount">0</span>
|
<span class="panel-count" id="todosCount">0</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-actions" onclick="event.stopPropagation()">
|
<div class="panel-actions" onclick="event.stopPropagation()">
|
||||||
<button class="btn btn-primary btn-sm" onclick="showAddTodoModal()">
|
<button class="btn btn-icon" onclick="showAddTodoModal()" title="Adaugă todo">
|
||||||
<i data-lucide="plus"></i>
|
<i data-lucide="plus"></i>
|
||||||
<span>Nou</span>
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1069,30 +1095,23 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="panel issues-panel" id="issuesPanel">
|
<!-- Activity Panel -->
|
||||||
<div class="panel-header" onclick="toggleSection('issuesPanel')">
|
<div class="panel activity-panel" id="activityPanel">
|
||||||
|
<div class="panel-header" onclick="toggleSection('activityPanel')">
|
||||||
<div class="panel-header-left">
|
<div class="panel-header-left">
|
||||||
<i data-lucide="chevron-down" class="panel-toggle"></i>
|
<i data-lucide="chevron-down" class="panel-toggle"></i>
|
||||||
<div class="panel-title">
|
<div class="panel-title">
|
||||||
<i data-lucide="check-square"></i>
|
<span>Activity</span>
|
||||||
<span>Issues</span>
|
|
||||||
</div>
|
</div>
|
||||||
<span class="panel-count" id="issuesCount">0</span>
|
<span class="panel-count" id="activityCount">0</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-actions" onclick="event.stopPropagation()">
|
<div class="panel-actions" onclick="event.stopPropagation()">
|
||||||
<button class="btn btn-primary btn-sm" onclick="showAddModal()">
|
<button class="btn btn-icon" onclick="refreshActivity()" title="Refresh">
|
||||||
<i data-lucide="plus"></i>
|
<i data-lucide="refresh-cw"></i>
|
||||||
<span>Nou</span>
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="issues-filters" id="issuesFilters">
|
<div class="panel-body" id="activityBody">
|
||||||
<button class="filter-btn active" data-filter="all">Toate</button>
|
|
||||||
<button class="filter-btn" data-filter="marius">👤 Marius</button>
|
|
||||||
<button class="filter-btn" data-filter="robert">👷 Robert</button>
|
|
||||||
<button class="filter-btn" data-filter="clawdbot">🤖 Clawdbot</button>
|
|
||||||
</div>
|
|
||||||
<div class="panel-body" id="issuesBody">
|
|
||||||
<div class="empty-state">
|
<div class="empty-state">
|
||||||
<i data-lucide="loader"></i>
|
<i data-lucide="loader"></i>
|
||||||
<p>Se încarcă...</p>
|
<p>Se încarcă...</p>
|
||||||
@@ -1279,6 +1298,23 @@
|
|||||||
updateStatusSummary();
|
updateStatusSummary();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function gitCommit() {
|
||||||
|
if (!confirm('Fac commit și push la toate modificările?')) return;
|
||||||
|
showToast('Se execută commit...', 'info');
|
||||||
|
try {
|
||||||
|
const response = await fetch('/echo/api/git-commit', { method: 'POST' });
|
||||||
|
const result = await response.json();
|
||||||
|
if (result.success) {
|
||||||
|
showToast('Commit reușit: ' + (result.files || 0) + ' fișiere', 'success');
|
||||||
|
setTimeout(refreshStatus, 1000);
|
||||||
|
} else {
|
||||||
|
showToast('Eroare: ' + (result.error || 'necunoscută'), 'error');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
showToast('Eroare la commit: ' + error.message, 'error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function refreshStatus() {
|
async function refreshStatus() {
|
||||||
showToast('Se reîmprospătează...');
|
showToast('Se reîmprospătează...');
|
||||||
await loadStatus();
|
await loadStatus();
|
||||||
@@ -1551,6 +1587,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="todo-content">
|
<div class="todo-content">
|
||||||
<div class="todo-text">${todo.text}</div>
|
<div class="todo-text">${todo.text}</div>
|
||||||
|
${todo.context ? `<div class="todo-context">${todo.context}</div>` : ''}
|
||||||
<div class="todo-meta">
|
<div class="todo-meta">
|
||||||
<span class="todo-domain ${todo.domain}">@${todo.domain}</span>
|
<span class="todo-domain ${todo.domain}">@${todo.domain}</span>
|
||||||
${todo.dueDate ? `<span class="todo-due ${isOverdue ? 'overdue' : ''}">${formatDate(todo.dueDate)}</span>` : ''}
|
${todo.dueDate ? `<span class="todo-due ${isOverdue ? 'overdue' : ''}">${formatDate(todo.dueDate)}</span>` : ''}
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
{
|
{
|
||||||
"lastUpdated": "2026-02-02T10:45:00Z",
|
"lastUpdated": "2026-02-02T10:52:00Z",
|
||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
"id": "prov-2026-02-02",
|
"id": "prov-2026-02-02",
|
||||||
"text": "Provocare: Observă când apare vocea critică și dă-i un nume ridicol",
|
"text": "Provocare: Alege UN lucru și scrie pe hârtie ce EFORT necesită. Întreabă-te: Îmi asum ASTA?",
|
||||||
|
"context": "Dacă da → fă-l. Dacă nu → ajustează sau renunță fără vinovăție.",
|
||||||
"domain": "self",
|
"domain": "self",
|
||||||
"dueDate": "2026-02-02",
|
"dueDate": "2026-02-02",
|
||||||
"done": false,
|
"done": false,
|
||||||
"doneAt": null,
|
"doneAt": null,
|
||||||
"source": "morning-coaching",
|
"source": "Zoltan Vereș - Motivația Intrinsecă",
|
||||||
"createdAt": "2026-02-02T09:00:00Z"
|
"createdAt": "2026-02-02T09:00:00Z"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user