frontend changes
This commit is contained in:
106
CLAUDE.md
106
CLAUDE.md
@@ -7,8 +7,9 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
||||
Deskmeter is a productivity tool that measures time spent across desktop workspaces. It consists of three main components:
|
||||
|
||||
- **dmcore**: Core tracking daemon (`dmapp/dmcore/main.py`) that monitors active workspace and task changes
|
||||
- **dmweb**: Flask web application (`dmapp/dmweb/`) for viewing productivity data
|
||||
- **dmfnt**: Angular frontend (`dmapp/dmfnt/`) for enhanced UI (in development)
|
||||
- **dmweb**: Flask web application (`dmapp/dmweb/`) for viewing productivity data with dark mode UI
|
||||
- **dmfnt**: Angular frontend (`dmapp/dmfnt/`) for enhanced UI (planned, not yet implemented)
|
||||
- **gnome-extension**: GNOME Shell extension for displaying current task in the top panel
|
||||
|
||||
## Architecture
|
||||
|
||||
@@ -31,10 +32,20 @@ Deskmeter is a productivity tool that measures time spent across desktop workspa
|
||||
### Web Interface Structure
|
||||
|
||||
**Flask Routes** (`dmapp/dmweb/dm.py`):
|
||||
- `/` - Today's productivity summary
|
||||
- `/day/<month>/<day>` - Single day view
|
||||
- `/calendar` - Monthly calendar view via `dmapp/dmweb/dmcal.py`
|
||||
- `/` - Today's productivity summary (large display with auto-refresh)
|
||||
- `/calendar/<scope>/<year>/<month>/<day>?grid=<1|3|6>` - Google Calendar-style view with aggregated task blocks
|
||||
- Scopes: `daily`, `weekly`, `monthly`
|
||||
- Grid: Hour aggregation (1h, 3h, or 6h blocks)
|
||||
- Shows only active workspaces (Plan/Think/Work) with gaps for idle time
|
||||
- Cascading overlapping blocks for multiple tasks per time period
|
||||
- `/switches/<scope>/<year>/<month>/<day>` - Raw switches view with proportional cell heights
|
||||
- Shows all workspace switches with time-based height visualization
|
||||
- `/work` - Work projects breakdown for today
|
||||
- `/totals` - All-time statistics
|
||||
- `/day/<month>/<day>` - Single day view
|
||||
- `/period/<start>/<end>` - Custom date range
|
||||
- `/api/current_task` - JSON endpoint for current task info (used by GNOME extension)
|
||||
- `/api/today` - HTML fragment for AJAX updates
|
||||
|
||||
## Development Commands
|
||||
|
||||
@@ -60,24 +71,26 @@ cd dmapp/tests
|
||||
python3 test_dmapp.py
|
||||
```
|
||||
|
||||
### Angular Frontend
|
||||
### Running the Web Interface
|
||||
|
||||
Use the `dmweb.sh` script for flexible deployment:
|
||||
|
||||
```bash
|
||||
cd dmapp/dmfnt
|
||||
cd /home/mariano/wdir/run
|
||||
|
||||
# Install dependencies
|
||||
npm install
|
||||
# Syntax: ./dmweb.sh <worktree> <port> <debug>
|
||||
./dmweb.sh dm-fend-updates 10002 1
|
||||
|
||||
# Development server
|
||||
npm run start
|
||||
|
||||
# Build for production
|
||||
npm run build
|
||||
|
||||
# Run tests
|
||||
npm run test
|
||||
# Parameters:
|
||||
# - worktree: directory name in /home/mariano/wdir/ (default: dm)
|
||||
# - port: Flask server port (default: 10000)
|
||||
# - debug: 1 for debug mode with auto-reload, 0 for production (default: 0)
|
||||
```
|
||||
|
||||
### Angular Frontend (Not Yet Implemented)
|
||||
|
||||
The Angular frontend (`dmapp/dmfnt/`) mentioned in the architecture is planned but not currently implemented. All current functionality is in the Flask templates.
|
||||
|
||||
### System Setup
|
||||
|
||||
The application requires:
|
||||
@@ -96,11 +109,66 @@ The application requires:
|
||||
|
||||
- The system enforces task constraints within work desktops - switching to a non-work task automatically reverts to the designated work task
|
||||
- Task files are monitored for changes to enable automatic context switching
|
||||
- Web interface runs on port 10000 by default
|
||||
- Web interface runs on port 10000 by default (configurable via `dmweb.sh` script)
|
||||
- Core daemon sleeps for 2 seconds between workspace checks
|
||||
|
||||
### UI/UX Design
|
||||
|
||||
**Dark Mode Theme** (applied across all views):
|
||||
- Background: `#1a1a1a`
|
||||
- Text: `#e0e0e0`
|
||||
- Accent/links: `#6b9bd1`
|
||||
- Borders: `#444`
|
||||
- Component backgrounds: `#2a2a2a`
|
||||
|
||||
**Calendar View Features**:
|
||||
- Hour-based aggregation (configurable: 1h, 3h, 6h grids)
|
||||
- Overlapping task blocks cascade right and down (8% horizontal, 4px vertical per task)
|
||||
- Only active workspaces shown (Plan/Think/Work) - idle time appears as gaps
|
||||
- Task colors generated via hash-based HSL for consistency
|
||||
- Height proportional to time spent in each grid period
|
||||
|
||||
**Switches View Features**:
|
||||
- Cell heights proportional to switch duration (30px min, 200px max)
|
||||
- Color-coded by task with hash-based HSL
|
||||
- Dark backgrounds with reduced opacity for idle workspaces
|
||||
|
||||
**Navigation**:
|
||||
- Consistent nav bar across all views: Today | Calendar | Switches | Work | All Time
|
||||
- All views interconnected for easy movement between different data perspectives
|
||||
|
||||
## GNOME Extension
|
||||
|
||||
A GNOME Shell extension displays the current task in the top panel:
|
||||
- Location: `gnome-extension/deskmeter-indicator@local/`
|
||||
- Polls `/api/current_task` endpoint
|
||||
- Updates on workspace switch with 2.2s debounce
|
||||
- Automatically truncates long task paths
|
||||
- Installation: `./gnome-extension/install.sh` or `./gnome-extension/update.sh`
|
||||
|
||||
## Key Implementation Details
|
||||
|
||||
**Calendar Aggregation** (`dmapp/dmweb/get_period_times.py:get_task_blocks_calendar()`):
|
||||
- Aggregates switches by configurable time grid (1h, 3h, or 6h)
|
||||
- Only includes active workspaces: Plan, Think, Work
|
||||
- Returns blocks with task_id, task_path, start time, duration, and hour
|
||||
- Filters out blocks shorter than `min_block_seconds`
|
||||
|
||||
**Task Path Resolution**:
|
||||
- Primary: `tasks` collection (current tasks)
|
||||
- Fallback: `task_history` collection (cached historical tasks)
|
||||
- Last resort: On-demand file search in task directory
|
||||
- Caching prevents repeated file I/O
|
||||
|
||||
**Switch Height Calculation** (switches view):
|
||||
- Finds max delta in current view
|
||||
- Heights scale linearly: `base_height + (ratio * (max_height - base_height))`
|
||||
- Base: 30px, Max: 200px
|
||||
|
||||
## Tool Development Guidelines
|
||||
|
||||
- This is a personal tool, not professionally developed
|
||||
- reuse as it is as much as possible unless refactor is required explicitly, suggest improvements
|
||||
- Reuse existing code as much as possible unless refactor is required explicitly
|
||||
- Only modify existing code if it absolutely doesn't make sense to add a new flow
|
||||
- When adding features, maintain the dark mode theme consistency
|
||||
- All new views should include the standard navigation bar
|
||||
@@ -1,23 +1,50 @@
|
||||
{% extends 'layout.html' %}
|
||||
|
||||
{% block head %}
|
||||
|
||||
{% block head %}
|
||||
|
||||
<style type="text/css">
|
||||
|
||||
body {
|
||||
background-color: #1a1a1a;
|
||||
color: #e0e0e0;
|
||||
margin: 20px;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.nav-bar {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-bottom: 30px;
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 2px solid #444;
|
||||
}
|
||||
|
||||
.nav-bar a {
|
||||
text-decoration: none;
|
||||
color: #6b9bd1;
|
||||
font-size: 12pt;
|
||||
padding: 5px 10px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.nav-bar a:hover {
|
||||
background-color: #2a2a2a;
|
||||
}
|
||||
|
||||
td > * {
|
||||
|
||||
}
|
||||
|
||||
td {
|
||||
vertical-align : top;
|
||||
vertical-align: top;
|
||||
height: 25px;
|
||||
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border: 1px solid black;
|
||||
border: 1px solid #444;
|
||||
background-color: #2a2a2a;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -25,8 +52,16 @@ table {
|
||||
{% endblock head %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
{% block content %}
|
||||
|
||||
{{ content | safe }}
|
||||
<div class="nav-bar">
|
||||
<a href="/">Today</a>
|
||||
<a href="/calendar/daily">Calendar</a>
|
||||
<a href="/switches/daily">Switches</a>
|
||||
<a href="/work">Work</a>
|
||||
<a href="/totals">All Time</a>
|
||||
</div>
|
||||
|
||||
{{ content | safe }}
|
||||
|
||||
{% endblock content %}
|
||||
@@ -9,6 +9,23 @@
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
.nav-bar {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.nav-bar a {
|
||||
text-decoration: none;
|
||||
color: #6b9bd1;
|
||||
font-size: 12pt;
|
||||
padding: 5px 10px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.nav-bar a:hover {
|
||||
background-color: #2a2a2a;
|
||||
}
|
||||
|
||||
.nav-tabs {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
@@ -169,6 +186,13 @@
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="nav-bar" style="margin-bottom: 15px; padding-bottom: 10px; border-bottom: 2px solid #444; font-size: 12pt;">
|
||||
<a href="/">Today</a>
|
||||
<a href="/switches/{{ scope }}/{{ base_date.year }}/{{ base_date.month }}/{{ base_date.day }}">Switches</a>
|
||||
<a href="/work">Work</a>
|
||||
<a href="/totals">All Time</a>
|
||||
</div>
|
||||
|
||||
<div class="nav-tabs">
|
||||
<a href="/calendar/daily/{{ base_date.year }}/{{ base_date.month }}/{{ base_date.day }}?grid={{ grid }}"
|
||||
class="{% if scope == 'daily' %}active{% endif %}">Daily</a>
|
||||
@@ -184,7 +208,6 @@
|
||||
class="{% if grid == 3 %}active{% endif %}" style="font-size: 11pt;">3h</a>
|
||||
<a href="/calendar/{{ scope }}/{{ base_date.year }}/{{ base_date.month }}/{{ base_date.day }}?grid=6"
|
||||
class="{% if grid == 6 %}active{% endif %}" style="font-size: 11pt;">6h</a>
|
||||
<a href="/switches/{{ scope }}/{{ base_date.year }}/{{ base_date.month }}/{{ base_date.day }}">View Switches</a>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -17,6 +17,27 @@
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
.nav-bar {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.nav-bar a {
|
||||
text-decoration: none;
|
||||
color: #6b9bd1;
|
||||
font-size: 11pt;
|
||||
padding: 5px 10px;
|
||||
border-radius: 3px;
|
||||
background-color: #2a2a2a;
|
||||
}
|
||||
|
||||
.nav-bar a:hover {
|
||||
background-color: #3a3a3a;
|
||||
}
|
||||
|
||||
.grey {
|
||||
color: #888;
|
||||
}
|
||||
@@ -57,6 +78,14 @@
|
||||
<!-- agregar función que me diga cuanto tiempo hace que esta activo el escritorio
|
||||
(calcular el delta con el ultimo switch y pasarlo a mm:ss) -->
|
||||
|
||||
<div class="nav-bar">
|
||||
<a href="/">Today</a>
|
||||
<a href="/calendar/daily">Calendar</a>
|
||||
<a href="/switches/daily">Switches</a>
|
||||
<a href="/work">Work</a>
|
||||
<a href="/totals">All Time</a>
|
||||
</div>
|
||||
|
||||
<div id="content-container">
|
||||
{% block content %}
|
||||
{% include 'main_content.html' %}
|
||||
|
||||
@@ -1,16 +1,81 @@
|
||||
{% extends 'layout.html' %}
|
||||
|
||||
{% block content %}
|
||||
{% block head %}
|
||||
<style>
|
||||
body {
|
||||
background-color: #1a1a1a;
|
||||
color: #e0e0e0;
|
||||
margin: 20px;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.nav-bar {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-bottom: 30px;
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 2px solid #444;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.nav-bar a {
|
||||
text-decoration: none;
|
||||
color: #6b9bd1;
|
||||
font-size: 12pt;
|
||||
padding: 5px 10px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.nav-bar a:hover {
|
||||
background-color: #2a2a2a;
|
||||
}
|
||||
|
||||
table {
|
||||
font-size: 24pt;
|
||||
border-collapse: collapse;
|
||||
width: auto;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 10px 40px 10px 0;
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
.grey {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.blue {
|
||||
color: #6b9bd1;
|
||||
}
|
||||
</style>
|
||||
{% endblock head %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="nav-bar">
|
||||
<a href="/">Today</a>
|
||||
<a href="/calendar/daily">Calendar</a>
|
||||
<a href="/switches/daily">Switches</a>
|
||||
<a href="/work">Work</a>
|
||||
<a href="/totals">All Time</a>
|
||||
</div>
|
||||
|
||||
<table>
|
||||
{% for row in rows %}
|
||||
{% for row in rows %}
|
||||
{% if row["ws"] in ['Away', 'Other'] %}
|
||||
{% set my_class = 'grey' %}
|
||||
{% elif row["ws"] in ['Active', 'Idle'] %}
|
||||
{% set my_class = 'blue' %}
|
||||
{% else %}
|
||||
{% set my_class = '' %}
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td>{{ row["ws"] }}</td>
|
||||
<td>{{ row["total"] }}</td>
|
||||
<td class="{{ my_class }}">{{ row["ws"] }}</td>
|
||||
<td class="{{ my_class }}">{{ row["total"] }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
{% endblock content %}
|
||||
@@ -9,6 +9,23 @@
|
||||
color: #e0e0e0;
|
||||
}
|
||||
|
||||
.nav-bar {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.nav-bar a {
|
||||
text-decoration: none;
|
||||
color: #6b9bd1;
|
||||
font-size: 12pt;
|
||||
padding: 5px 10px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.nav-bar a:hover {
|
||||
background-color: #2a2a2a;
|
||||
}
|
||||
|
||||
.nav-tabs {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
@@ -122,6 +139,13 @@
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="nav-bar" style="margin-bottom: 15px; padding-bottom: 10px; border-bottom: 2px solid #444;">
|
||||
<a href="/">Today</a>
|
||||
<a href="/calendar/{{ scope }}/{{ base_date.year }}/{{ base_date.month }}/{{ base_date.day }}">Calendar</a>
|
||||
<a href="/work">Work</a>
|
||||
<a href="/totals">All Time</a>
|
||||
</div>
|
||||
|
||||
<div class="nav-tabs">
|
||||
<a href="/switches/daily/{{ base_date.year }}/{{ base_date.month }}/{{ base_date.day }}"
|
||||
class="{% if scope == 'daily' %}active{% endif %}">Daily</a>
|
||||
@@ -129,9 +153,6 @@
|
||||
class="{% if scope == 'weekly' %}active{% endif %}">Weekly</a>
|
||||
<a href="/switches/monthly/{{ base_date.year }}/{{ base_date.month }}/{{ base_date.day }}"
|
||||
class="{% if scope == 'monthly' %}active{% endif %}">Monthly</a>
|
||||
<span style="margin-left: auto;">
|
||||
<a href="/calendar/{{ scope }}/{{ base_date.year }}/{{ base_date.month }}/{{ base_date.day }}">View Calendar</a>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="date-nav">
|
||||
|
||||
Reference in New Issue
Block a user