mirror of
https://github.com/DRYTRIX/TimeTracker.git
synced 2026-05-03 19:00:13 -05:00
fix(ui): unify Recent Time Entries actions and enable self-delete
- Dashboard: switch Actions column to inline `btn-group` with `btn-action` styles (no stacking), preserving delete modal and permission checks. - Tasks view: add Actions column with Edit/Delete, plus delete confirmation modal and JS; regular users can delete their own entries (or admins any). - Timer page: align dynamic recent entries buttons to `btn-action` styles. Server-side permissions already enforce owner-or-admin and block deleting active timers. Files: app/templates/main/dashboard.html, app/templates/tasks/view.html, templates/timer/timer.html
This commit is contained in:
@@ -260,13 +260,13 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="text-end pe-4 actions-cell" data-label="Actions">
|
||||
<div class="btn-group d-flex d-md-inline-flex mobile-stack" role="group">
|
||||
<div class="btn-group" role="group">
|
||||
<a href="{{ url_for('timer.edit_timer', timer_id=entry.id) }}"
|
||||
class="btn btn-sm btn-outline-secondary touch-target" title="Edit entry">
|
||||
class="btn btn-sm btn-action btn-action--edit touch-target" title="Edit entry">
|
||||
<i class="fas fa-edit"></i>
|
||||
</a>
|
||||
{% if current_user.is_admin or entry.user_id == current_user.id %}
|
||||
<button type="button" class="btn btn-sm btn-outline-danger touch-target" title="Delete entry"
|
||||
<button type="button" class="btn btn-sm btn-action btn-action--danger touch-target" title="Delete entry"
|
||||
onclick="showDeleteEntryModal('{{ entry.id }}', '{{ entry.project.name }}', '{{ entry.duration_formatted }}')">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
|
||||
@@ -175,6 +175,7 @@
|
||||
<th>Duration</th>
|
||||
<th>Notes</th>
|
||||
<th>User</th>
|
||||
<th class="text-end">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -190,6 +191,20 @@
|
||||
</td>
|
||||
<td>{{ entry.notes[:50] if entry.notes else '-' }}</td>
|
||||
<td>{{ entry.user.display_name if entry.user else '-' }}</td>
|
||||
<td class="text-end">
|
||||
<div class="btn-group" role="group">
|
||||
<a href="{{ url_for('timer.edit_timer', timer_id=entry.id) }}"
|
||||
class="btn btn-sm btn-outline-primary" title="Edit">
|
||||
<i class="fas fa-edit"></i>
|
||||
</a>
|
||||
{% if current_user.is_admin or entry.user_id == current_user.id %}
|
||||
<button type="button" class="btn btn-sm btn-outline-danger" title="Delete"
|
||||
onclick="showDeleteEntryModal('{{ entry.id }}', '{{ task.project.name }}', '{{ entry.duration_formatted }}')">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
@@ -560,5 +575,63 @@ function updateTaskStatus(status) {
|
||||
form.submit();
|
||||
}
|
||||
}
|
||||
|
||||
// Function to show delete time entry modal
|
||||
function showDeleteEntryModal(entryId, projectName, duration) {
|
||||
const nameEl = document.getElementById('deleteEntryProjectName');
|
||||
const durationEl = document.getElementById('deleteEntryDuration');
|
||||
const formEl = document.getElementById('deleteEntryForm');
|
||||
if (nameEl) nameEl.textContent = projectName || '';
|
||||
if (durationEl) durationEl.textContent = duration || '';
|
||||
if (formEl) formEl.action = "{{ url_for('timer.delete_timer', timer_id=0) }}".replace('0', entryId);
|
||||
const modal = document.getElementById('deleteEntryModal');
|
||||
if (modal) new bootstrap.Modal(modal).show();
|
||||
}
|
||||
|
||||
// Loading state on delete submit
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const deleteForm = document.getElementById('deleteEntryForm');
|
||||
if (deleteForm) {
|
||||
deleteForm.addEventListener('submit', function() {
|
||||
const btn = deleteForm.querySelector('button[type="submit"]');
|
||||
if (btn) {
|
||||
btn.innerHTML = '<div class="loading-spinner me-2"></div>Deleting...';
|
||||
btn.disabled = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- Delete Time Entry Modal -->
|
||||
<div class="modal fade" id="deleteEntryModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">
|
||||
<i class="fas fa-trash me-2 text-danger"></i>Delete Time Entry
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="alert alert-warning">
|
||||
<i class="fas fa-exclamation-triangle me-2"></i>
|
||||
<strong>Warning:</strong> This action cannot be undone.
|
||||
</div>
|
||||
<p>Are you sure you want to delete the time entry for <strong id="deleteEntryProjectName"></strong>?</p>
|
||||
<p class="text-muted mb-0">Duration: <strong id="deleteEntryDuration"></strong></p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
||||
<i class="fas fa-times me-1"></i>Cancel
|
||||
</button>
|
||||
<form method="POST" id="deleteEntryForm" class="d-inline">
|
||||
<button type="submit" class="btn btn-danger">
|
||||
<i class="fas fa-trash me-2"></i>Delete Entry
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -428,10 +428,10 @@ function loadRecentEntries() {
|
||||
<div class="badge bg-primary fs-6 mb-2">${entry.duration_formatted}</div>
|
||||
<br>
|
||||
<div class="btn-group" role="group">
|
||||
<button class="btn btn-sm btn-outline-primary" onclick="editEntry(${entry.id})" title="Edit entry">
|
||||
<button class="btn btn-sm btn-action btn-action--edit" onclick="editEntry(${entry.id})" title="Edit entry">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-danger" onclick="deleteEntry(${entry.id})" title="Delete entry">
|
||||
<button class="btn btn-sm btn-action btn-action--danger" onclick="deleteEntry(${entry.id})" title="Delete entry">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user