tasks for specific sub categories
This commit is contained in:
41
app.py
41
app.py
@@ -49,16 +49,39 @@ def index():
|
|||||||
current_entry['activity_name'] = active_activity['name']
|
current_entry['activity_name'] = active_activity['name']
|
||||||
current_entry['activity_color'] = active_activity.get('color', '#3498db')
|
current_entry['activity_color'] = active_activity.get('color', '#3498db')
|
||||||
|
|
||||||
# 1. Tasks generated specifically for this session (time_entry_id linked)
|
# Logic for fetching tasks:
|
||||||
# 2. Open tasks linked to this activity type (contextual todos)
|
# 1. Fetch Session Specific Tasks (linked via time_entry_id)
|
||||||
active_tasks = list(db.tasks.find({
|
session_tasks = list(db.tasks.find({
|
||||||
'user_id': user_id,
|
'user_id': user_id,
|
||||||
'status': 'open',
|
'status': 'open',
|
||||||
'$or': [
|
'time_entry_id': current_entry['_id']
|
||||||
{'time_entry_id': current_entry['_id']},
|
|
||||||
{'activity_id': current_entry['activity_id'], 'is_template': False, 'time_entry_id': None}
|
|
||||||
]
|
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
# 2. Fetch Contextual Tasks (linked via activity_id, no time_entry_id)
|
||||||
|
context_criteria = {
|
||||||
|
'user_id': user_id,
|
||||||
|
'status': 'open',
|
||||||
|
'activity_id': current_entry['activity_id'],
|
||||||
|
'is_template': False,
|
||||||
|
'time_entry_id': None
|
||||||
|
}
|
||||||
|
|
||||||
|
current_subcat = current_entry.get('subcategory')
|
||||||
|
|
||||||
|
if current_subcat:
|
||||||
|
# If active entry has subcategory: Show tasks matching that subcategory OR general tasks (no subcategory)
|
||||||
|
context_criteria['$or'] = [
|
||||||
|
{'subcategory': current_subcat},
|
||||||
|
{'subcategory': {'$in': [None, '']}}
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
# If active entry has NO subcategory: Show only General tasks (no subcategory assigned)
|
||||||
|
# This hides specific subcategory tasks when just tracking the general activity
|
||||||
|
context_criteria['subcategory'] = {'$in': [None, '']}
|
||||||
|
|
||||||
|
context_tasks = list(db.tasks.find(context_criteria))
|
||||||
|
|
||||||
|
active_tasks = session_tasks + context_tasks
|
||||||
|
|
||||||
return render_template('dashboard.html',
|
return render_template('dashboard.html',
|
||||||
activities=activities,
|
activities=activities,
|
||||||
@@ -361,6 +384,7 @@ def create_task():
|
|||||||
|
|
||||||
name = request.form['name']
|
name = request.form['name']
|
||||||
activity_id = request.form.get('activity_id')
|
activity_id = request.form.get('activity_id')
|
||||||
|
subcategory = request.form.get('subcategory', '') # Get subcategory
|
||||||
due_date_str = request.form.get('due_date')
|
due_date_str = request.form.get('due_date')
|
||||||
is_template = 'is_template' in request.form
|
is_template = 'is_template' in request.form
|
||||||
|
|
||||||
@@ -371,7 +395,8 @@ def create_task():
|
|||||||
'is_template': is_template,
|
'is_template': is_template,
|
||||||
'source': 'manual', # Mark as manually created
|
'source': 'manual', # Mark as manually created
|
||||||
'created_at': datetime.now(),
|
'created_at': datetime.now(),
|
||||||
'comments': []
|
'comments': [],
|
||||||
|
'subcategory': subcategory # Save subcategory
|
||||||
}
|
}
|
||||||
|
|
||||||
if activity_id:
|
if activity_id:
|
||||||
|
|||||||
@@ -60,6 +60,11 @@
|
|||||||
<a href="{{ url_for('task_detail', task_id=task._id) }}" class="task-name-link" style="text-decoration: none; color: var(--text-primary); font-weight: 500; {% if task.status == 'completed' %}text-decoration: line-through; color: var(--text-secondary);{% endif %}">
|
<a href="{{ url_for('task_detail', task_id=task._id) }}" class="task-name-link" style="text-decoration: none; color: var(--text-primary); font-weight: 500; {% if task.status == 'completed' %}text-decoration: line-through; color: var(--text-secondary);{% endif %}">
|
||||||
{{ task.name }}
|
{{ task.name }}
|
||||||
</a>
|
</a>
|
||||||
|
{% if task.subcategory %}
|
||||||
|
<span style="font-size: 0.75rem; color: #555; background: #eee; padding: 2px 6px; border-radius: 4px;">
|
||||||
|
{{ task.subcategory }}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
{% if task.due_date %}
|
{% if task.due_date %}
|
||||||
<span style="font-size: 0.75rem; color: var(--text-secondary); background: var(--bg-input); padding: 2px 6px; border-radius: 4px;">
|
<span style="font-size: 0.75rem; color: var(--text-secondary); background: var(--bg-input); padding: 2px 6px; border-radius: 4px;">
|
||||||
{{ task.due_date.strftime('%d. %b %H:%M') }}
|
{{ task.due_date.strftime('%d. %b %H:%M') }}
|
||||||
@@ -108,6 +113,11 @@
|
|||||||
<a href="{{ url_for('task_detail', task_id=task._id) }}" style="text-decoration: none; color: var(--text-primary); font-weight: 500; {% if task.status == 'completed' %}text-decoration: line-through; color: var(--text-secondary);{% endif %}">
|
<a href="{{ url_for('task_detail', task_id=task._id) }}" style="text-decoration: none; color: var(--text-primary); font-weight: 500; {% if task.status == 'completed' %}text-decoration: line-through; color: var(--text-secondary);{% endif %}">
|
||||||
{{ task.name }}
|
{{ task.name }}
|
||||||
</a>
|
</a>
|
||||||
|
{% if task.subcategory %}
|
||||||
|
<span style="font-size: 0.75rem; color: #555; background: #eee; padding: 2px 6px; border-radius: 4px;">
|
||||||
|
{{ task.subcategory }}
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
{% if task.due_date %}
|
{% if task.due_date %}
|
||||||
<span style="font-size: 0.75rem; color: var(--text-secondary); background: var(--bg-input); padding: 2px 6px; border-radius: 4px;">
|
<span style="font-size: 0.75rem; color: var(--text-secondary); background: var(--bg-input); padding: 2px 6px; border-radius: 4px;">
|
||||||
{{ task.due_date.strftime('%d. %b %H:%M') }}
|
{{ task.due_date.strftime('%d. %b %H:%M') }}
|
||||||
@@ -156,13 +166,20 @@
|
|||||||
<input type="text" name="name" id="modalInputName" required placeholder="What needs to be done?" autocomplete="off">
|
<input type="text" name="name" id="modalInputName" required placeholder="What needs to be done?" autocomplete="off">
|
||||||
|
|
||||||
<label>Activity</label>
|
<label>Activity</label>
|
||||||
<select name="activity_id" id="modalSelectActivity">
|
<select name="activity_id" id="modalSelectActivity" onchange="updateModalSubcategories()">
|
||||||
<option value="">-- No Activity --</option>
|
<option value="">-- No Activity --</option>
|
||||||
{% for act in activities %}
|
{% for act in activities %}
|
||||||
<option value="{{ act._id }}">{{ act.name }}</option>
|
<option value="{{ act._id }}">{{ act.name }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<div id="modalSubcatWrapper" style="display:none;">
|
||||||
|
<label>Subcategory</label>
|
||||||
|
<select name="subcategory" id="modalSelectSubcategory">
|
||||||
|
<option value="">-- None --</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<label>Due Date</label>
|
<label>Due Date</label>
|
||||||
<input type="datetime-local" name="due_date">
|
<input type="datetime-local" name="due_date">
|
||||||
|
|
||||||
@@ -184,6 +201,39 @@
|
|||||||
|
|
||||||
<!-- Scripts removed dead macros -->
|
<!-- Scripts removed dead macros -->
|
||||||
<script>
|
<script>
|
||||||
|
// Prepare Data for JS
|
||||||
|
const activitiesList = [
|
||||||
|
{% for act in activities %}
|
||||||
|
{
|
||||||
|
id: "{{ act._id }}",
|
||||||
|
subcategories: {{ act.subcategories|default([])|tojson }}
|
||||||
|
},
|
||||||
|
{% endfor %}
|
||||||
|
];
|
||||||
|
|
||||||
|
function updateModalSubcategories() {
|
||||||
|
const actSelect = document.getElementById('modalSelectActivity');
|
||||||
|
const subWrapper = document.getElementById('modalSubcatWrapper');
|
||||||
|
const subSelect = document.getElementById('modalSelectSubcategory');
|
||||||
|
|
||||||
|
const selectedId = actSelect.value;
|
||||||
|
const activity = activitiesList.find(a => a.id === selectedId);
|
||||||
|
|
||||||
|
subSelect.innerHTML = '<option value="">-- None --</option>';
|
||||||
|
|
||||||
|
if (activity && activity.subcategories && activity.subcategories.length > 0) {
|
||||||
|
subWrapper.style.display = 'block';
|
||||||
|
activity.subcategories.forEach(sub => {
|
||||||
|
const opt = document.createElement('option');
|
||||||
|
opt.value = sub;
|
||||||
|
opt.innerText = sub;
|
||||||
|
subSelect.appendChild(opt);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
subWrapper.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function openTaskModal(activityId) {
|
function openTaskModal(activityId) {
|
||||||
const modal = document.getElementById('taskModal');
|
const modal = document.getElementById('taskModal');
|
||||||
const select = document.getElementById('modalSelectActivity');
|
const select = document.getElementById('modalSelectActivity');
|
||||||
@@ -195,6 +245,9 @@
|
|||||||
select.value = "";
|
select.value = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Trigger subcategory update based on pre-selection
|
||||||
|
updateModalSubcategories();
|
||||||
|
|
||||||
modal.classList.add('show');
|
modal.classList.add('show');
|
||||||
nameInput.focus();
|
nameInput.focus();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user