diff --git a/src/views/Entries.vue b/src/views/Entries.vue
index b0a93d5..b2c6ecd 100644
--- a/src/views/Entries.vue
+++ b/src/views/Entries.vue
@@ -94,6 +94,16 @@
-
+
+
+ {{ getTagName(tagId) }}
+
+
|
{{ formatDuration(entry.duration) }}
@@ -174,6 +184,12 @@
/>
+
+
+
@@ -257,14 +273,19 @@ import AppNumberInput from '../components/AppNumberInput.vue'
import AppSelect from '../components/AppSelect.vue'
import AppDatePicker from '../components/AppDatePicker.vue'
import AppDiscardDialog from '../components/AppDiscardDialog.vue'
+import AppTagInput from '../components/AppTagInput.vue'
import { useEntriesStore, type TimeEntry } from '../stores/entries'
import { useProjectsStore } from '../stores/projects'
+import { useTagsStore } from '../stores/tags'
import { formatDate } from '../utils/locale'
import { useFormGuard } from '../utils/formGuard'
import { renderMarkdown } from '../utils/markdown'
const entriesStore = useEntriesStore()
const projectsStore = useProjectsStore()
+const tagsStore = useTagsStore()
+const entryTags = ref>({})
+const editEntryTags = ref([])
const { showDiscardDialog, snapshot: snapshotForm, tryClose: tryCloseForm, confirmDiscard, cancelDiscard } = useFormGuard()
@@ -362,6 +383,28 @@ function formatDuration(seconds: number): string {
return `${minutes}m`
}
+// Tag helper functions
+function getTagName(tagId: number): string {
+ const tag = tagsStore.tags.find(t => t.id === tagId)
+ return tag?.name || ''
+}
+
+function getTagColor(tagId: number): string {
+ const tag = tagsStore.tags.find(t => t.id === tagId)
+ return tag?.color || '#6B7280'
+}
+
+async function loadEntryTags() {
+ const tags: Record = {}
+ for (const entry of entriesStore.entries) {
+ if (entry.id) {
+ const entryTagList = await tagsStore.getEntryTags(entry.id)
+ tags[entry.id] = entryTagList.map(t => t.id!).filter(id => id != null)
+ }
+ }
+ entryTags.value = tags
+}
+
// Duplicate an entry with current timestamp
async function duplicateEntry(entry: TimeEntry) {
const now = new Date()
@@ -375,6 +418,7 @@ async function duplicateEntry(entry: TimeEntry) {
}
await entriesStore.createEntry(newEntry)
await entriesStore.fetchEntries()
+ await loadEntryTags()
}
// Copy yesterday's entries to today
@@ -401,6 +445,7 @@ async function copyPreviousDay() {
})
}
await entriesStore.fetchEntries()
+ await loadEntryTags()
}
// Copy last week's entries shifted forward 7 days
@@ -428,23 +473,26 @@ async function copyPreviousWeek() {
})
}
await entriesStore.fetchEntries()
+ await loadEntryTags()
}
// Apply filters
-function applyFilters() {
- entriesStore.fetchEntries(startDate.value || undefined, endDate.value || undefined)
+async function applyFilters() {
+ await entriesStore.fetchEntries(startDate.value || undefined, endDate.value || undefined)
+ await loadEntryTags()
}
// Clear filters
-function clearFilters() {
+async function clearFilters() {
startDate.value = ''
endDate.value = ''
filterProject.value = null
- entriesStore.fetchEntries()
+ await entriesStore.fetchEntries()
+ await loadEntryTags()
}
// Open edit dialog
-function openEditDialog(entry: TimeEntry) {
+async function openEditDialog(entry: TimeEntry) {
editingEntry.value = entry
editForm.id = entry.id || 0
editForm.project_id = entry.project_id
@@ -460,6 +508,14 @@ function openEditDialog(entry: TimeEntry) {
editHour.value = dt.getHours()
editMinute.value = dt.getMinutes()
+ // Load tags for this entry
+ if (entry.id) {
+ const tags = await tagsStore.getEntryTags(entry.id)
+ editEntryTags.value = tags.map(t => t.id!).filter(id => id != null)
+ } else {
+ editEntryTags.value = []
+ }
+
snapshotForm(getEditFormData())
showEditDialog.value = true
}
@@ -488,6 +544,13 @@ async function handleEdit() {
}
await entriesStore.updateEntry(updatedEntry)
+
+ // Save tags for the edited entry
+ if (editForm.id) {
+ await tagsStore.setEntryTags(editForm.id, editEntryTags.value)
+ await loadEntryTags()
+ }
+
closeEditDialog()
}
}
@@ -516,9 +579,12 @@ async function handleDelete() {
onMounted(async () => {
await Promise.all([
entriesStore.fetchEntries(),
- projectsStore.fetchProjects()
+ projectsStore.fetchProjects(),
+ tagsStore.fetchTags()
])
+ await loadEntryTags()
+
// Set default date range to this week
const now = new Date()
const weekStart = new Date(now)
diff --git a/src/views/Timer.vue b/src/views/Timer.vue
index c4d6b51..c625cc5 100644
--- a/src/views/Timer.vue
+++ b/src/views/Timer.vue
@@ -104,6 +104,10 @@
+
@@ -183,10 +187,12 @@ import { useToastStore } from '../stores/toast'
import { Timer as TimerIcon, RotateCcw, ExternalLink, Star } from 'lucide-vue-next'
import { invoke } from '@tauri-apps/api/core'
import AppSelect from '../components/AppSelect.vue'
+import AppTagInput from '../components/AppTagInput.vue'
import IdlePromptDialog from '../components/IdlePromptDialog.vue'
import AppTrackingPromptDialog from '../components/AppTrackingPromptDialog.vue'
import { formatDateTime } from '../utils/locale'
import { useFavoritesStore, type Favorite } from '../stores/favorites'
+import { useTagsStore } from '../stores/tags'
const timerStore = useTimerStore()
const projectsStore = useProjectsStore()
@@ -194,12 +200,14 @@ const entriesStore = useEntriesStore()
const settingsStore = useSettingsStore()
const toastStore = useToastStore()
const favoritesStore = useFavoritesStore()
+const tagsStore = useTagsStore()
const favorites = computed(() => favoritesStore.favorites)
// Local state for inputs
const selectedProject = ref(timerStore.selectedProjectId)
const selectedTask = ref(timerStore.selectedTaskId)
const description = ref(timerStore.description)
+const selectedTags = ref([])
const projectTasks = ref([])
// Split timer into parts for colon animation
@@ -300,7 +308,7 @@ async function openMiniTimer() {
}
// Toggle timer
-function toggleTimer() {
+async function toggleTimer() {
if (timerStore.isStopped) {
if (!selectedProject.value) {
toastStore.info('Please select a project before starting the timer')
@@ -309,7 +317,16 @@ function toggleTimer() {
timerStore.start()
} else {
timerStore.stop()
- entriesStore.fetchEntries()
+ await entriesStore.fetchEntries()
+
+ // Save tags for the new entry if any were selected
+ if (selectedTags.value.length > 0) {
+ const entries = entriesStore.entries
+ if (entries.length > 0 && entries[0].id) {
+ await tagsStore.setEntryTags(entries[0].id, selectedTags.value)
+ }
+ }
+ selectedTags.value = []
}
}
@@ -390,7 +407,8 @@ onMounted(async () => {
projectsStore.fetchProjects(),
entriesStore.fetchEntries(),
settingsStore.fetchSettings(),
- favoritesStore.fetchFavorites()
+ favoritesStore.fetchFavorites(),
+ tagsStore.fetchTags()
])
// Restore timer state
|