From b5b469b9033041558234c06c5fadf69fd97da610 Mon Sep 17 00:00:00 2001 From: callumalpass Date: Mon, 8 Sep 2025 20:44:11 +1000 Subject: [PATCH 1/2] fix: standardize custom property identifiers to prevent duplication Custom properties were appearing duplicated on task cards when configured both in settings and filter bar due to inconsistent identifier formats: - Settings used raw keys (e.g., "testText") - Filter bar used prefixed format (e.g., "user:field_123") This caused TaskCard to render both as separate properties, showing duplicate entries like "Test Text" and "TestText". Changes: - Update appearanceTab.ts to use consistent user: prefixed format - Aligns settings behavior with PropertyVisibilityDropdown format - Ensures single source of truth for custom property identification Resolves custom properties duplication issue. --- src/settings/tabs/appearanceTab.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/settings/tabs/appearanceTab.ts b/src/settings/tabs/appearanceTab.ts index 24f78d7a..bd560430 100644 --- a/src/settings/tabs/appearanceTab.ts +++ b/src/settings/tabs/appearanceTab.ts @@ -54,7 +54,7 @@ export function renderAppearanceTab(container: HTMLElement, plugin: TaskNotesPlu plugin.settings.userFields.forEach(field => { if (field.displayName && field.key) { propertyGroups.user.push({ - key: field.key, + key: `user:${field.id}`, label: field.displayName }); } From 02a1ef27c33d9ea0cf26faca6db9a5911fde0846 Mon Sep 17 00:00:00 2001 From: callumalpass Date: Mon, 8 Sep 2025 20:46:26 +1000 Subject: [PATCH 2/2] fix: improve total tracked time property visibility control Resolves issues where total tracked time was showing on task cards even when the property wasn't explicitly enabled, and ensures it only displays when the value is greater than 0 minutes. Changes: - Remove legacy fallback that automatically displayed time tracking info - Add > 0 check to totalTrackedTime property renderer - Update tests to reflect new expected behavior - Add tests for explicit property enabling and zero-value handling Now total tracked time only appears when: 1. The totalTrackedTime property is explicitly enabled in settings/filter 2. The tracked time value is greater than 0 minutes This gives users proper control over when time tracking information is displayed on their task cards. --- src/ui/TaskCard.ts | 38 +--------------------------------- tests/unit/ui/TaskCard.test.ts | 32 +++++++++++++++++++++++++++- 2 files changed, 32 insertions(+), 38 deletions(-) diff --git a/src/ui/TaskCard.ts b/src/ui/TaskCard.ts index b579693d..0a5c2298 100644 --- a/src/ui/TaskCard.ts +++ b/src/ui/TaskCard.ts @@ -303,7 +303,7 @@ const PROPERTY_RENDERERS: Record = { } }, 'totalTrackedTime': (element, value, _, plugin) => { - if (typeof value === 'number') { + if (typeof value === 'number' && value > 0) { element.textContent = `${plugin.formatTime(value)} tracked`; } }, @@ -1108,24 +1108,6 @@ export function createTaskCard(task: TaskInfo, plugin: TaskNotesPlugin, visibleP } } - // Legacy: Add time spent information if timeEstimate or totalTrackedTime properties are not explicitly configured - const timeSpent = calculateTotalTimeSpent(task.timeEntries || []); - const hasTimeEstimate = propertiesToShow.includes('timeEstimate'); - const hasTotalTrackedTime = propertiesToShow.includes('totalTrackedTime'); - if (!hasTimeEstimate && !hasTotalTrackedTime && (task.timeEstimate || timeSpent > 0)) { - const timeInfo: string[] = []; - if (timeSpent > 0) { - timeInfo.push(`${plugin.formatTime(timeSpent)} spent`); - } - if (task.timeEstimate) { - timeInfo.push(`${plugin.formatTime(task.timeEstimate)} estimated`); - } - const timeSpan = metadataLine.createEl('span', { - cls: 'task-card__metadata-property task-card__metadata-property--time' - }); - timeSpan.textContent = timeInfo.join(', '); - metadataElements.push(timeSpan); - } // Add separators between metadata elements addMetadataSeparators(metadataLine, metadataElements); @@ -1620,24 +1602,6 @@ export function updateTaskCard(element: HTMLElement, task: TaskInfo, plugin: Tas } } - // Legacy: Add time spent information if timeEstimate or totalTrackedTime properties are not explicitly configured - const timeSpent = calculateTotalTimeSpent(task.timeEntries || []); - const hasTimeEstimate = propertiesToShow.includes('timeEstimate'); - const hasTotalTrackedTime = propertiesToShow.includes('totalTrackedTime'); - if (!hasTimeEstimate && !hasTotalTrackedTime && (task.timeEstimate || timeSpent > 0)) { - const timeInfo: string[] = []; - if (timeSpent > 0) { - timeInfo.push(`${plugin.formatTime(timeSpent)} spent`); - } - if (task.timeEstimate) { - timeInfo.push(`${plugin.formatTime(task.timeEstimate)} estimated`); - } - const timeSpan = metadataLine.createEl('span', { - cls: 'task-card__metadata-property task-card__metadata-property--time' - }); - timeSpan.textContent = timeInfo.join(', '); - metadataElements.push(timeSpan); - } // Add separators between metadata elements addMetadataSeparators(metadataLine, metadataElements); diff --git a/tests/unit/ui/TaskCard.test.ts b/tests/unit/ui/TaskCard.test.ts index bc55acb9..899104a9 100644 --- a/tests/unit/ui/TaskCard.test.ts +++ b/tests/unit/ui/TaskCard.test.ts @@ -332,8 +332,38 @@ describe('TaskCard Component', () => { expect(metadataLine?.textContent).toContain('Due:'); expect(metadataLine?.textContent).toContain('Scheduled:'); expect(metadataLine?.textContent).toContain('@work, @urgent'); - expect(metadataLine?.textContent).toContain('30m spent'); + // Time tracking info should only show when explicitly configured as visible properties + expect(metadataLine?.textContent).not.toContain('30m spent'); + expect(metadataLine?.textContent).not.toContain('60m estimated'); + }); + + it('should show time tracking properties when explicitly enabled', () => { + const task = TaskFactory.createTask({ + timeEstimate: 60, + timeEntries: [{ startTime: '2025-01-15T10:00:00Z', endTime: '2025-01-15T10:30:00Z' }], + totalTrackedTime: 30 + }); + + // Test with timeEstimate and totalTrackedTime properties explicitly enabled + const visibleProperties = ['timeEstimate', 'totalTrackedTime']; + const card = createTaskCard(task, mockPlugin, visibleProperties); + const metadataLine = card.querySelector('.task-card__metadata'); + expect(metadataLine?.textContent).toContain('60m estimated'); + expect(metadataLine?.textContent).toContain('30m tracked'); + }); + + it('should not show totalTrackedTime when value is 0', () => { + const task = TaskFactory.createTask({ + totalTrackedTime: 0 + }); + + // Enable totalTrackedTime property but value is 0 + const visibleProperties = ['totalTrackedTime']; + const card = createTaskCard(task, mockPlugin, visibleProperties); + const metadataLine = card.querySelector('.task-card__metadata'); + + expect(metadataLine?.textContent).not.toContain('tracked'); }); it('should create clickable project links for wikilink projects', () => {