feat: standalone focus items with edit, convert, project tab, domain ordering
- Add standalone text line items to focus (quick-add with optional domain) - Edit page for standalone items (title, domain, project) - Convert standalone items to task, note, link, or list item - Focus tab on project detail page showing assigned focus items - Sort domain groups: General first, then by domain sort_order - Add domain_id and title to nullable_fields in BaseRepository Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,18 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick add -->
|
||||
<form action="/focus/quick-add" method="post" class="flex items-center gap-2 mb-3">
|
||||
<input type="text" name="title" class="form-input" placeholder="Add item to focus..." required style="flex:1;padding:6px 10px;font-size:0.85rem;">
|
||||
<select name="quick_domain_id" class="filter-select" style="min-width:120px;padding:6px 8px;font-size:0.82rem;">
|
||||
<option value="">No Domain</option>
|
||||
{% for d in domains %}
|
||||
<option value="{{ d.id }}">{{ d.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<button type="submit" class="btn btn-primary btn-sm">+ Add</button>
|
||||
</form>
|
||||
|
||||
<!-- Focus items grouped by domain -->
|
||||
{% if items %}
|
||||
<div class="card">
|
||||
@@ -39,10 +51,10 @@
|
||||
</form>
|
||||
</td>
|
||||
<td style="padding:1px 3px;vertical-align:middle;color:var(--muted);font-size:0.78rem;white-space:nowrap;">{{ item.due_date or '' }}</td>
|
||||
<td style="padding:1px 1px;vertical-align:middle;">{% if item.task_id %}<span class="priority-dot priority-{{ item.priority }}"></span>{% elif item.list_item_id %}<span style="color:var(--muted);font-size:0.85rem;">☰</span>{% endif %}</td>
|
||||
<td style="padding:1px 3px;vertical-align:middle;{{ 'text-decoration:line-through;' if item.completed }}">{% if item.task_id %}{% if item.title %}<a href="/tasks/{{ item.task_id }}" class="focus-title">{{ item.title }}</a>{% else %}<span style="color:var(--muted)">[Deleted]</span>{% endif %}{% elif item.list_item_id %}{% if item.list_item_content %}<a href="/lists/{{ item.list_item_list_id }}" class="focus-title">{{ item.list_item_content }}</a>{% else %}<span style="color:var(--muted)">[Deleted]</span>{% endif %}{% endif %}</td>
|
||||
<td style="padding:1px 1px;vertical-align:middle;">{% if item.task_id %}<span class="priority-dot priority-{{ item.priority }}"></span>{% elif item.list_item_id %}<span style="color:var(--muted);font-size:0.85rem;">☰</span>{% else %}<span style="color:var(--muted);font-size:0.85rem;">●</span>{% endif %}</td>
|
||||
<td style="padding:1px 3px;vertical-align:middle;{{ 'text-decoration:line-through;' if item.completed }}">{% if item.task_id %}{% if item.task_title %}<a href="/tasks/{{ item.task_id }}" class="focus-title">{{ item.task_title }}</a>{% else %}<span style="color:var(--muted)">[Deleted]</span>{% endif %}{% elif item.list_item_id %}{% if item.list_item_content %}<a href="/lists/{{ item.list_item_list_id }}" class="focus-title">{{ item.list_item_content }}</a>{% else %}<span style="color:var(--muted)">[Deleted]</span>{% endif %}{% else %}<a href="/focus/{{ item.id }}/edit" class="focus-title">{{ item.title }}</a>{% endif %}</td>
|
||||
<td style="padding:1px 3px;vertical-align:middle;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">{% if item.area_name %}<span class="row-tag">{{ item.area_name }}</span>{% endif %}</td>
|
||||
<td style="padding:1px 3px;vertical-align:middle;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">{% if item.task_id and item.project_name %}<span class="row-tag" style="background:var(--accent-soft);color:var(--accent)">{{ item.project_name }}</span>{% elif item.list_item_id and item.list_name %}<span class="row-tag" style="background:var(--purple);color:#fff">{{ item.list_name }}</span>{% endif %}</td>
|
||||
<td style="padding:1px 3px;vertical-align:middle;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">{% if item.project_name %}<span class="row-tag" style="background:var(--accent-soft);color:var(--accent)">{{ item.project_name }}</span>{% elif item.list_item_id and item.list_name %}<span class="row-tag" style="background:var(--purple);color:#fff">{{ item.list_name }}</span>{% endif %}</td>
|
||||
<td style="padding:1px 3px;vertical-align:middle;text-align:right;color:var(--muted);font-size:0.78rem;">{{ '~%smin'|format(item.estimated_minutes) if item.estimated_minutes else '' }}</td>
|
||||
<td style="padding:1px 1px;vertical-align:middle;">
|
||||
<form action="/focus/{{ item.id }}/remove" method="post" style="display:inline">
|
||||
|
||||
85
templates/focus_edit.html
Normal file
85
templates/focus_edit.html
Normal file
@@ -0,0 +1,85 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="breadcrumb">
|
||||
<a href="/focus">Focus</a>
|
||||
<span class="sep">/</span>
|
||||
<span>Edit Item</span>
|
||||
</div>
|
||||
|
||||
<div class="page-header">
|
||||
<h1 class="page-title">Edit Focus Item</h1>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<form method="post" action="/focus/{{ item.id }}/edit">
|
||||
<div class="form-grid">
|
||||
<div class="form-group full-width">
|
||||
<label class="form-label">Title *</label>
|
||||
<input type="text" name="title" class="form-input" required
|
||||
value="{{ item.title or '' }}">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">Domain</label>
|
||||
<select name="domain_id" class="form-select">
|
||||
<option value="">-- No Domain --</option>
|
||||
{% for d in domains %}
|
||||
<option value="{{ d.id }}"
|
||||
{{ 'selected' if item.domain_id and item.domain_id|string == d.id|string }}>
|
||||
{{ d.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">Project</label>
|
||||
<select name="project_id" class="form-select">
|
||||
<option value="">-- No Project --</option>
|
||||
{% for p in projects %}
|
||||
<option value="{{ p.id }}"
|
||||
{{ 'selected' if item.project_id and item.project_id|string == p.id|string }}>
|
||||
{{ p.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button type="submit" class="btn btn-primary">Save Changes</button>
|
||||
<a href="/focus" class="btn btn-secondary">Cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="card" style="margin-top:16px;">
|
||||
<div style="padding:16px;">
|
||||
<h3 style="margin:0 0 12px;font-size:14px;color:var(--muted);">Convert to...</h3>
|
||||
<div style="display:flex;flex-wrap:wrap;gap:8px;align-items:end;">
|
||||
<form action="/focus/{{ item.id }}/convert-to-task" method="post" data-confirm="Convert to task? Opens the task editor." style="display:inline">
|
||||
<button type="submit" class="btn btn-secondary btn-sm">Task</button>
|
||||
</form>
|
||||
<form action="/focus/{{ item.id }}/convert-to-note" method="post" data-confirm="Convert to note? Opens the note editor." style="display:inline">
|
||||
<button type="submit" class="btn btn-secondary btn-sm">Note</button>
|
||||
</form>
|
||||
<form action="/focus/{{ item.id }}/convert-to-link" method="post" data-confirm="Convert to link? Opens the link editor." style="display:inline">
|
||||
<button type="submit" class="btn btn-secondary btn-sm">Link</button>
|
||||
</form>
|
||||
<form action="/focus/{{ item.id }}/convert-to-list-item" method="post" data-confirm="Add to selected list?" style="display:inline-flex;gap:6px;align-items:end;">
|
||||
<select name="list_id" class="form-select" style="min-width:160px;height:32px;font-size:13px;" required>
|
||||
<option value="">Select list...</option>
|
||||
{% for l in lists %}
|
||||
<option value="{{ l.id }}">{{ l.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<button type="submit" class="btn btn-secondary btn-sm">List Item</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top:12px;display:flex;justify-content:flex-end;">
|
||||
<form action="/focus/{{ item.id }}/remove" method="post" data-confirm="Delete this focus item?" style="display:inline">
|
||||
<button type="submit" class="btn btn-danger btn-sm">Delete</button>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -40,6 +40,7 @@
|
||||
<a href="/projects/{{ item.id }}?tab=lists" class="tab-item {{ 'active' if tab == 'lists' }}">Lists{% if counts.lists %} ({{ counts.lists }}){% endif %}</a>
|
||||
<a href="/projects/{{ item.id }}?tab=decisions" class="tab-item {{ 'active' if tab == 'decisions' }}">Decisions{% if counts.decisions %} ({{ counts.decisions }}){% endif %}</a>
|
||||
<a href="/projects/{{ item.id }}?tab=meetings" class="tab-item {{ 'active' if tab == 'meetings' }}">Meetings{% if counts.meetings %} ({{ counts.meetings }}){% endif %}</a>
|
||||
<a href="/projects/{{ item.id }}?tab=focus" class="tab-item {{ 'active' if tab == 'focus' }}">Focus{% if counts.focus %} ({{ counts.focus }}){% endif %}</a>
|
||||
<a href="/projects/{{ item.id }}?tab=processes" class="tab-item {{ 'active' if tab == 'processes' }}">Processes</a>
|
||||
<a href="/projects/{{ item.id }}?tab=contacts" class="tab-item {{ 'active' if tab == 'contacts' }}">Contacts{% if counts.contacts %} ({{ counts.contacts }}){% endif %}</a>
|
||||
</div>
|
||||
@@ -162,6 +163,20 @@
|
||||
<div class="empty-state"><div class="empty-state-text">No meetings linked to this project</div></div>
|
||||
{% endfor %}
|
||||
|
||||
{% elif tab == 'focus' %}
|
||||
{% for f in tab_data %}
|
||||
<div class="list-row">
|
||||
<span class="row-title"><a href="/focus/{{ f.id }}/edit">{{ f.title }}</a></span>
|
||||
{% if f.domain_name %}<span class="row-tag" style="{% if f.domain_color %}border-color:{{ f.domain_color }};color:{{ f.domain_color }}{% endif %}">{{ f.domain_name }}</span>{% endif %}
|
||||
<span class="row-meta">{{ f.created_at.strftime('%Y-%m-%d') if f.created_at else '' }}</span>
|
||||
<div class="row-actions">
|
||||
<a href="/focus/{{ f.id }}/edit" class="btn btn-ghost btn-xs">Edit</a>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="empty-state"><div class="empty-state-text">No focus items assigned to this project</div></div>
|
||||
{% endfor %}
|
||||
|
||||
{% elif tab == 'processes' %}
|
||||
<div class="empty-state"><div class="empty-state-text">Process management coming soon</div></div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user