2025-06-15 04:02:57 +00:00
# TaskNotes Plugin: Architecture & Developer's Guide
## 1. Introduction & Guiding Principles
This guide is designed to help you understand the architecture of the TaskNotes plugin, ensuring that new features and updates are implemented in a way that is consistent, maintainable, and performant.
The architecture of this plugin is built on several key principles:
2025-06-17 20:28:30 +00:00
* **Separation of Concerns:** Logic is separated into distinct layers: UI (Views & Components), Business Logic (Services), and Data (Minimal Cache & Obsidian Native Cache). This makes the codebase easier to reason about and test.
* **Native-First Data Access:** Obsidian's `metadataCache` is the primary source of truth for all task and note data. The minimal cache layer exists primarily to coordinate event signals and maintain only performance-critical indexes.
* **Unidirectional Data Flow:** Changes flow in one direction: User Action -> Service -> File System -> Native Cache -> Event Coordination -> UI Update. This predictable pattern prevents complex state management issues and race conditions.
* **Event-Driven Communication:** Components are decoupled through centralized event coordination. The minimal cache coordinates view updates efficiently, preventing multiple views from redundantly scanning files.
* **Performance Through Coordination:** Rather than complex indexing, performance is achieved through intelligent event coordination, lazy computation, and leveraging Obsidian's optimized native cache.
2025-06-15 04:02:57 +00:00
* **Configuration-Driven:** Core functionalities like statuses, priorities, and field names are not hard-coded. They are managed by dedicated services (`StatusManager`, `PriorityManager` , `FieldMapper` ) that interpret user settings, making the plugin highly customizable.
docs: Expand Tasknotes Development Guidelines with Performance Optimization and External Integration Best Practices
Summary:
• Added a new bullet under key architectural principles for "Obsidian Optimization Compliance" to indicate that the plugin follows Obsidian's load time optimization and deferred view compatibility best practices.
• Introduced a comprehensive "Performance Optimization & Obsidian Best Practices" section outlining strategies for keeping onload() lightweight, deferring heavy services until layout readiness, and dynamically importing heavy modules.
• Added detailed guidance on deferred view compatibility, including proper view initialization patterns and safe workspace iteration practices.
• Included a "File System Event Handling" subsection with patterns for registering vault events post-layout readiness, using debouncing, and ensuring event handlers do not interfere with startup performance.
• Added a new "External Data Integration" section describing the architecture for ICS calendar integration (both remote and local), file watcher patterns, and recommendations for integrating new external data sources with caching and UI configuration.
• Expanded error handling and data validation guidance to include safe date parsing with examples, optional property handling in interfaces, and developer best practices for type safety.
• Added a new "Testing & Quality Assurance" section with manual testing checklists and performance metrics to ensure robust plugin operation across different startup conditions and usage scenarios.
This update enhances the development guidelines by clearly documenting advanced performance strategies, integration patterns for external data sources, and comprehensive best practices for ensuring the plugin’s maintainability and compatibility with the latest Obsidian versions.
2025-06-16 11:20:49 +00:00
* **Obsidian Optimization Compliance:** The plugin follows Obsidian's best practices for load time optimization and deferred view compatibility, ensuring fast startup and smooth integration with the latest Obsidian versions.
2025-06-15 04:02:57 +00:00
## 2. High-Level Architecture Diagram
2025-06-17 20:28:30 +00:00
This diagram illustrates the flow of data and events within the plugin, emphasizing the native-first approach:
2025-06-15 04:02:57 +00:00
```
+----------------+ +------------------+ +------------------+
| User Input |------>| UI / Views |------>| Services |
| (Click, Drag) | | (Agenda, Kanban) | | (TaskService, etc) |
+----------------+ +------------------+ +------------------+
^ |
| | (1. Write to file)
| v
| +------------+
| (5. UI Update via | File System|
| DOMReconciler) | (.md) |
| +------------+
2025-06-17 20:28:30 +00:00
| |
| | (2. Native metadata update)
+---------------------+ v
2025-06-15 04:02:57 +00:00
+---------------------+ | +------------------+
2025-06-17 20:28:30 +00:00
| DOMReconciler | | (4. Coordinated view | Obsidian Native | (Primary Source
| (Efficient Updates) |< ---- + updates ) | MetadataCache | of Truth )
2025-06-15 04:02:57 +00:00
+---------------------+ | +------------------+
| |
2025-06-17 20:28:30 +00:00
| | (3. Event coordination)
| v
2025-06-15 04:02:57 +00:00
+-----------------------------------+
2025-06-17 20:28:30 +00:00
| MinimalCache (Event Coordinator)|
| - Essential indexes only |
| - Coordinates view refreshes |
2025-06-15 04:02:57 +00:00
+-----------------------------------+
```
## 3. Directory Structure
The project is organized to reflect the architectural layers:
* `/src/`
* `main.ts` : The plugin's entry point. It initializes all services, views, and commands.
* `types.ts` : **Crucial.** Contains all shared type definitions. All new types should be added here.
* `/views/` : Contains the primary UI views (`TaskListView`, `AgendaView` , `KanbanView` , etc.), which are `ItemView` implementations registered with Obsidian.
* `/ui/` : Contains reusable, "dumb" UI components like `TaskCard` , `NoteCard` , and `FilterBar` . These components are responsible for rendering data, not fetching it.
* `/modals/` : Contains all modals for user interaction (`TaskCreationModal`, `TaskEditModal` , etc.).
* `/services/` : The core business logic of the plugin resides here. Each service has a specific responsibility (e.g., `TaskService` for CRUD, `FilterService` for querying, `PomodoroService` for timers).
* `/editor/` : Contains CodeMirror extensions that enhance the Obsidian editor, like `TaskLinkWidget` and `InstantConvertButtons` .
2025-06-17 20:28:30 +00:00
* `/utils/` : Contains helper classes and functions that support the entire plugin, such as `MinimalNativeCache` , `dateUtils` , and `DOMReconciler` .
2025-06-15 04:02:57 +00:00
* `/settings/` : Contains the settings tab UI and default settings configuration.
* `/styles/` : Contains all CSS files, which are compiled into a single `styles.css` .
## 4. Key Architectural Concepts
### 4.1. The Data Flow: A Step-by-Step Guide
2025-06-17 20:28:30 +00:00
Understanding this native-first flow is the most important part of contributing to the plugin.
2025-06-15 04:02:57 +00:00
1. **User Action** : A user interacts with the UI (e.g., clicks "Archive" on a `TaskCard` ).
2. **Service Call** : The UI component's event handler calls the relevant method in a service (e.g., `plugin.taskService.toggleArchive(task)` ). **UI components should never modify data directly.**
3. **File System Write** : The service performs the necessary changes on the Markdown file's frontmatter.
2025-06-17 20:28:30 +00:00
4. **Native Cache Update** : Obsidian's native metadata cache automatically updates with the new file content.
5. **Minimal Cache Coordination** : The minimal cache detects the native change and updates only essential indexes, then coordinates view refresh events.
6. **Event Emission** : The minimal cache emits coordinated events (e.g., `EVENT_TASK_UPDATED` ) to prevent redundant view updates.
7. **Coordinated View Refresh** : Views receive coordinated events and refresh efficiently, fetching fresh data directly from the native metadata cache.
8. **DOM Reconciliation** : Views use the `DOMReconciler` to efficiently update only the parts of the UI that have changed.
### 4.2. The Minimal Cache - Event Coordinator & Performance Guardian
The `MinimalNativeCache` serves as an intelligent coordinator rather than a data warehouse. Its primary purpose is **view performance coordination** , not data storage.
* **Core Philosophy** : Leverage Obsidian's native metadata cache maximally while coordinating view updates efficiently.
* **What it Does** :
* **Event Coordination** : Prevents multiple views from simultaneously scanning files by coordinating refresh signals
* **Essential Indexing** : Maintains only 3 performance-critical indexes: `tasksByDate` , `tasksByStatus` , `overdueTasks`
* **Native Integration** : Listens to Obsidian's native metadata events and translates them to coordinated view updates
* **Lazy Computation** : Computes tags, contexts, and priorities on-demand rather than pre-indexing
* **What it Doesn't Do** :
* **Data Storage** : Task data comes directly from `app.metadataCache.getFileCache()`
* **Complex Indexing** : No redundant data structures duplicating native cache
* **Note Management** : Notes handled by Obsidian's daily notes interface
* **The 3 Essential Indexes Explained** :
```typescript
// Only these are indexed for performance:
tasksByDate: Map< string , Set < string > > // Calendar view optimization
tasksByStatus: Map< string , Set < string > > // FilterService optimization
overdueTasks: Set< string > // Overdue query optimization
// Everything else computed on-demand:
getAllTags() -> scans native cache when called
getAllPriorities() -> scans native cache when called
getTasksByPriority() -> filters all tasks when called
```
* **Performance Benefits of Coordination** :
```typescript
// Without coordination: Multiple views scan independently
CalendarView -> scans 1000 files for date tasks
AgendaView -> scans 1000 files for date tasks
KanbanView -> scans 1000 files for status tasks
// Result: 3000 file scans on data change
// With coordination: Single coordinated update
MinimalCache -> coordinates single refresh signal
All views -> refresh once with targeted data
// Result: 1 coordinated update cycle
```
2025-06-15 04:02:57 +00:00
2025-06-17 20:28:30 +00:00
* **Developer Best Practices** :
* **Read from native cache** : Use `app.metadataCache.getFileCache(file)` for direct data access
* **Coordinate through minimal cache** : Use cache for event coordination and essential indexes only
* **Never duplicate data** : Don't store data that's already in the native cache
* **Leverage lazy computation** : Compute infrequently-accessed data on-demand
* **Update essential indexes** : When adding date/status-related features, consider index impact
2025-06-15 04:02:57 +00:00
2025-06-17 20:28:30 +00:00
### 4.3. The Event System - Coordinated Communication
2025-06-15 04:02:57 +00:00
2025-06-17 20:28:30 +00:00
The event system now focuses on **coordination efficiency** rather than complex pub/sub patterns.
2025-06-15 04:02:57 +00:00
2025-06-17 20:28:30 +00:00
* **Purpose** : Coordinate view updates efficiently while preventing redundant operations. The minimal cache serves as an intelligent event dispatcher.
* **Coordination Patterns** :
```typescript
// Efficient: Coordinated update
minimalCache.on('file-updated', (data) => {
// All views receive coordinated signal
// Each view refreshes with fresh native cache data
});
// Inefficient: Direct native listening (avoided)
app.metadataCache.on('changed', (file) => {
// Each view independently processes the same change
// Results in redundant scanning and processing
});
```
2025-06-15 04:02:57 +00:00
2025-06-17 20:28:30 +00:00
* **Event Coordination Benefits** :
* **Prevents Duplicate Work** : Single file change doesn't trigger multiple view scans
* **Batched Updates** : Multiple rapid changes can be batched into single refresh
* **Performance Isolation** : Slow views don't impact fast views through coordination
2025-06-15 04:02:57 +00:00
* **Developer Best Practices** :
2025-06-17 20:28:30 +00:00
* **Use coordinated events** : Listen to minimal cache events, not native cache directly
* **Fetch fresh data** : On event receipt, fetch fresh data from native cache
* **Avoid event proliferation** : Don't create multiple event types for the same data change
2025-06-15 04:02:57 +00:00
### 4.4. Date and Time Management (`dateUtils.ts`)
2025-08-02 12:54:11 +00:00
Handling dates and times is notoriously difficult due to timezones and different formats. This plugin standardizes date/time handling through `dateUtils.ts` and implements the UTC Anchor principle for robust timezone-independent logic.
#### The UTC Anchor Principle
The UTC Anchor principle is a fundamental architectural decision that ensures timezone-independent date handling throughout the plugin.
* **The Problem** : JavaScript's `new Date()` is inconsistent. `new Date('2023-10-27')` creates a UTC date, while `new Date('2023-10-27T10:00:00')` creates a local timezone date. This leads to "off-by-one-day" errors and inconsistent behavior across timezones.
* **The Solution** : The UTC Anchor principle establishes that all date-only strings (e.g., "2025-08-01") are represented internally as Date objects anchored to midnight UTC. This provides a canonical representation where the string "2025-08-01" maps to the exact same internal timestamp for every user on Earth.
* **Implementation** :
```typescript
// For internal logic (comparisons, sorting, filtering)
const date = parseDateToUTC('2025-08-01'); // Always 2025-08-01T00:00:00.000Z
// For UI display (showing dates to users)
const date = parseDateToLocal('2025-08-01'); // Midnight in user's timezone
// Deprecated - do not use directly
const date = parseDate('2025-08-01'); // Legacy function, aliased to parseDateToLocal
```
* **Key Benefits** :
* **Absolute Consistency** : Same date string always produces same timestamp internally
* **Simplified Logic** : Direct timestamp comparisons work correctly
* **Timezone Independence** : Users in different timezones see consistent behavior
* **Future-Proof** : Eliminates entire classes of timezone bugs
2025-06-15 04:02:57 +00:00
* **Developer Best Practices** :
2025-08-02 12:54:11 +00:00
* **Never use `new Date(dateString)` directly.** Always use the appropriate parsing function from `dateUtils.ts` .
* **For internal logic** : Use `parseDateToUTC()` for all date comparisons, sorting, filtering, and business logic.
* **For UI display** : Use `parseDateToLocal()` when showing dates to users or handling user input.
* **Check for time components** : Use `hasTimeComponent(dateString)` to determine if a date string includes time information:
```typescript
if (hasTimeComponent(dateString)) {
// Has time - use local parsing for display
const dateTime = parseDateToLocal(dateString);
} else {
// Date-only - use UTC anchor for logic
const date = parseDateToUTC(dateString);
}
```
* **For comparisons** : Use the provided safe functions that implement UTC anchors: `isSameDateSafe` , `isBeforeDateSafe` , `isOverdueTimeAware` .
* **For storage** : Always store dates in YYYY-MM-DD format using `formatDateForStorage()` .
* **For timestamps** : When creating `dateCreated` or `dateModified` , use `getCurrentTimestamp()` for timezone-aware ISO strings.
* **Migration Pattern** : When updating existing code:
```typescript
// Old pattern (fragile)
const date = parseDate(task.due);
if (isBefore(date, today)) { ... }
// New pattern (robust)
const date = parseDateToUTC(task.due); // For logic
if (isBeforeDateSafe(task.due, getTodayString())) { ... }
```
2025-06-15 04:02:57 +00:00
### 4.5. The UI Layer (Views and Components)
2025-06-17 20:28:30 +00:00
* **Views (`/views/`)** : These are the main panels of the plugin (e.g., `AgendaView` ). They are stateful and responsible for fetching data (via direct native cache access or `FilterService` ), managing user interactions, and orchestrating the rendering of their content. They should contain the `FilterBar` and the main content display.
* **Native-First Data Access** :
```typescript
// Views now access data directly from native cache
async refreshTasks(): Promise< void > {
// Get task paths from minimal cache (indexed)
const taskPaths = this.plugin.cacheManager.getTasksForDate(dateStr);
// Get fresh task data from native cache
const tasks = await Promise.all(
taskPaths.map(path => {
const file = this.app.vault.getAbstractFileByPath(path);
const metadata = this.app.metadataCache.getFileCache(file);
return this.extractTaskInfo(path, metadata.frontmatter);
})
);
this.renderTasks(tasks);
}
```
2025-06-15 04:02:57 +00:00
* **Reusable Components (`/ui/`)** : These are "dumb" components like `TaskCard` and `NoteCard` .
* They receive data as props (`createTaskCard(task, plugin, options)`).
* They are responsible only for rendering that data into HTML.
* They should not contain business logic. Any user interaction (like a button click) should call a method on the `plugin` or a `service` passed in as a prop.
2025-06-17 20:28:30 +00:00
* **DOMReconciler** : To ensure high performance, views do not re-render their entire HTML on every data change. Instead, they use `plugin.domReconciler.updateList()` . This utility efficiently diffs the new data against the existing DOM, only adding, removing, or updating the elements that have changed.
2025-06-15 04:02:57 +00:00
### 4.6. The Field Mapper (`FieldMapper.ts`) - The Data Translator
This is a critical architectural component that enables user customization.
* **Purpose** : The `FieldMapper` is a "translator" service. Its primary purpose is to decouple the plugin's internal `TaskInfo` property names (e.g., `scheduled` , `timeEstimate` ) from the user-configurable property names in the YAML frontmatter of their task files. This allows users to name their properties whatever they like (e.g., `schedule_on` , `estimate_minutes` ) without breaking the plugin.
* **How it Works** : It provides a two-way mapping.
2025-06-17 20:28:30 +00:00
* **Reading (File -> `TaskInfo`)** : When processing native metadata cache data, the frontmatter is passed to `fieldMapper.mapFromFrontmatter(frontmatter)` . The service uses the mapping in `settings.fieldMapping` to create a standardized `TaskInfo` object. For example, if the user setting is `{ due: "deadline" }` , the mapper will take `frontmatter.deadline` and put its value into the `taskInfo.due` field.
2025-06-15 04:02:57 +00:00
* **Writing (`TaskInfo` -> File)** : When `TaskService` saves a task, it passes the internal `TaskInfo` object to `fieldMapper.mapToFrontmatter(taskInfo)` . This creates a frontmatter object ready for serialization. For example, `taskInfo.due` will be written as `deadline: ...` in the YAML.
* **Developer Best Practices** :
2025-06-17 20:28:30 +00:00
* **Central Point of Interaction** : Any service that directly reads or writes task frontmatter (`MinimalNativeCache`, `TaskService` ) **must** use the `FieldMapper` .
2025-06-15 04:02:57 +00:00
* **Stable Internal API** : Within the plugin's TypeScript code (views, components, other services), you should **always** interact with the standardized `TaskInfo` properties (`task.due`, `task.priority` , etc.). The `FieldMapper` is the boundary layer that handles the translation to/from the user's world.
* **Avoid Hard-coding** : **Never** write code that directly accesses a frontmatter property like `frontmatter.due` . Always use the mapper to get the user-configured field name first.
* **Extensibility** : When adding a new persistent property to tasks, you must add it to the `FieldMapping` type in `types.ts` , the `DEFAULT_FIELD_MAPPING` in `settings.ts` , and the mapping logic in `FieldMapper.ts` .
## 5. Developer's Guide: How to Implement Common Changes
### 5.1. Adding a New Property to Tasks
Let's say you want to add a `complexity: 'simple' | 'medium' | 'hard'` property to tasks.
1. **Update `types.ts`** : Add `complexity?: string;` to the `TaskInfo` interface.
2. **Update `settings.ts`** :
* Add `complexity: string;` to the `FieldMapping` interface in `DEFAULT_FIELD_MAPPING` .
* Add a new setting in the `TaskNotesSettingTab` to allow users to configure the property name.
3. **Update `FieldMapper.ts`** : Add logic to `mapFromFrontmatter` and `mapToFrontmatter` to handle the new `complexity` field.
4. **Update `TaskService.ts`** :
* In `createTask` , handle the new property, possibly applying a default value.
* In `updateTask` , ensure the new property can be updated.
Refactor and consolidate modal implementation, update naming and imports, and adjust styles and tests
• Remove the legacy “MinimalistTaskModal” base class and its derivatives (MinimalistTaskCreationModal and MinimalistTaskEditModal) by renaming and consolidating them into new classes:
– Rename MinimalistTaskModal to TaskModal
– Rename MinimalistTaskCreationModal → TaskCreationModal
– Rename MinimalistTaskEditModal → TaskEditModal
• Update all references and imports across the project (including AdvancedCalendarView) to use the new TaskModal, TaskCreationModal, and TaskEditModal classes instead of the old minimalist versions.
• Extract and expose a new TaskConversionOptions type (in src/types/taskConversion.ts) to provide a consistent interface for passing conversion-related options.
• Adjust the modal logic:
– In TaskCreationModal, update natural language parsing, pre-populated values, and form handling using the new base TaskModal APIs.
– In TaskEditModal, change the constructor signature to accept an options object (including “task” and an optional “onTaskUpdated” callback) and update recurrence handling to convert legacy recurrence objects into display strings.
• Update CSS:
– Rename styles/minimalist-modal.css to styles/task-modal.css and update class comments (e.g. “MINIMALIST TASK MODAL” → “TASK MODAL – Google Keep/Todoist Inspired”).
– Modify selectors in modal-bem.css by removing references to “.task-creation-modal” and “.task-edit-modal” in some cases, as these are now included under the unified “tasknotes-plugin” context.
• Remove the tests for BaseTaskModal (tests/unit/modals/BaseTaskModal.test.ts) since that base class is no longer used, and update test references for the new TaskCreationModal class.
• Overall, this commit streamlines the modal codebase and unifies the naming and styling of task-related modals while updating the type definitions and downstream usage in views and tests.
These changes are backward‐compatible with previous plugin settings (aside from renamed classes/interfaces) but may require updates in any custom integrations relying on the old MinimalistTask* modals.
2025-06-27 11:45:08 +00:00
5. **Update `TaskModal.ts`** : Add a dropdown or input field to `TaskCreationModal` and `TaskEditModal` to allow users to set the complexity.
2025-06-15 04:02:57 +00:00
6. **Update `TaskCard.ts`** : In `createTaskCard` and `updateTaskCard` , add logic to display the new complexity information (e.g., an icon or text in the metadata line).
2025-06-17 20:28:30 +00:00
7. **Update `FilterService.ts` (Optional)** : If you want to filter by complexity frequently:
* Consider whether an index is needed (probably not - compute on-demand)
2025-06-15 04:02:57 +00:00
* Add logic to `FilterService.matchesQuery` to filter by complexity.
* Add a complexity filter control to `FilterBar.ts` .
2025-06-17 20:28:30 +00:00
**Note**: With the minimal cache approach, most new properties should be computed on-demand rather than indexed. Only add indexes for frequently-accessed, performance-critical queries.
2025-07-27 02:05:25 +00:00
### 5.2. Adding View-Specific Options to Saved Views
The plugin supports capturing and restoring view-specific display options as part of saved views. This feature allows views to preserve their display preferences (toggles, visibility options) alongside filter configurations.
#### Implementation Pattern
**Step 1: Define View Options in the View Class**
```typescript
export class MyView extends ItemView {
private showOption1: boolean = true;
private showOption2: boolean = false;
private setupViewOptions(): void {
// Configure FilterBar with view options
this.filterBar.setViewOptions([
{ id: 'showOption1', label: 'Show Option 1', value: this.showOption1 },
{ id: 'showOption2', label: 'Show Option 2', value: this.showOption2 }
]);
}
}
```
**Step 2: Handle View Options Events**
```typescript
private setupEventListeners(): void {
// Save view options along with filter state
this.filterBar.on('saveView', ({ name, query, viewOptions }) => {
this.plugin.viewStateManager.saveView(name, query, viewOptions);
});
// Apply loaded view options
this.filterBar.on('loadViewOptions', (viewOptions: {[key: string]: boolean}) => {
this.applyViewOptions(viewOptions);
});
}
private applyViewOptions(viewOptions: {[key: string]: boolean}): void {
// Apply options to internal state
if (viewOptions.hasOwnProperty('showOption1')) {
this.showOption1 = viewOptions.showOption1;
}
if (viewOptions.hasOwnProperty('showOption2')) {
this.showOption2 = viewOptions.showOption2;
}
// Update FilterBar to reflect loaded state
this.setupViewOptions();
// Refresh view to apply changes
this.refresh();
}
```
**Step 3: FilterBar Integration**
The FilterBar automatically handles:
- Capturing current view options when saving views
- Emitting `loadViewOptions` events when loading saved views
- Providing UI controls for view-specific options
#### Architecture Components
**SavedView Interface Enhancement:**
```typescript
export interface SavedView {
id: string;
name: string;
query: FilterQuery;
viewOptions?: {[key: string]: boolean}; // View-specific display options
}
```
**ViewStateManager Integration:**
```typescript
saveView(name: string, query: FilterQuery, viewOptions?: {[key: string]: boolean}): SavedView {
const view: SavedView = {
id: this.generateId(),
name,
query: FilterUtils.deepCloneFilterQuery(query),
viewOptions: viewOptions ? { ...viewOptions } : undefined
};
// ... save logic
}
```
#### Current Implementation Examples
**Agenda View Options:**
- `showOverdueOnToday` : Shows overdue tasks in today's section
- `showNotes` : Controls display of daily notes
**Advanced Calendar View Options:**
- `showScheduled` : Display tasks with scheduled dates
- `showDue` : Display tasks with due dates
- `showTimeblocks` : Display time-blocking entries
- `showRecurring` : Display recurring task events
- `showICSEvents` : Display imported calendar events
- `showTimeEntries` : Display time tracking entries
#### Developer Best Practices
**View Option Design:**
- Use boolean options for simple toggles
- Keep option IDs descriptive and unique per view
- Provide sensible defaults for all options
- Consider backward compatibility when adding new options
**State Management:**
- Always use defensive programming when checking for option existence
- Apply options to internal state before updating UI
- Refresh the view after applying loaded options
- Maintain option state independently of saved views
**Performance Considerations:**
- View options are cloned when saving/loading for data safety
- Options are applied synchronously to avoid UI state conflicts
- FilterBar updates are batched to prevent unnecessary re-renders
2025-08-02 12:54:11 +00:00
### 5.3. Migrating to UTC Anchor Pattern
When updating existing code or adding new date-handling features, follow this migration guide:
**Step 1: Identify Date Usage Context**
```typescript
// Is this for internal logic?
if (purposeIsLogic) {
// Use UTC anchor: comparisons, sorting, filtering, storage
const date = parseDateToUTC(dateString);
}
// Is this for UI display?
if (purposeIsDisplay) {
// Use local parsing: showing to users, form inputs
const date = parseDateToLocal(dateString);
}
```
**Step 2: Update Import Statements**
```typescript
// Old
import { parseDate, isBeforeDate } from '../utils/dateUtils';
// New
import { parseDateToUTC, parseDateToLocal, isBeforeDateSafe } from '../utils/dateUtils';
```
**Step 3: Replace parseDate Calls**
```typescript
// Old pattern
const dueDate = parseDate(task.due);
const scheduledDate = parseDate(task.scheduled);
// New pattern - for logic
const dueDate = parseDateToUTC(task.due);
const scheduledDate = parseDateToUTC(task.scheduled);
// New pattern - for display
const dueDateDisplay = parseDateToLocal(task.due);
const formattedDate = format(dueDateDisplay, 'MMM d, yyyy');
```
**Step 4: Update Comparisons**
```typescript
// Old pattern
const date1 = parseDate(dateStr1);
const date2 = parseDate(dateStr2);
if (isBefore(date1, date2)) { ... }
// New pattern - use safe comparison functions
if (isBeforeDateSafe(dateStr1, dateStr2)) { ... }
// Or if you need the Date objects
const date1 = parseDateToUTC(dateStr1);
const date2 = parseDateToUTC(dateStr2);
if (date1.getTime() < date2.getTime ( ) ) { . . . }
```
**Step 5: Handle Mixed Date/DateTime**
```typescript
// When dealing with both date-only and datetime strings
function processTaskDate(dateString: string) {
if (hasTimeComponent(dateString)) {
// Has time - might need local handling for display
const dateTime = parseDateToLocal(dateString);
return format(dateTime, 'MMM d, h:mm a');
} else {
// Date only - use UTC anchor for consistency
const date = parseDateToUTC(dateString);
return format(date, 'MMM d');
}
}
```
### 5.4. Walkthrough: Modifying a Task Property (Native-First Approach)
2025-06-15 04:02:57 +00:00
Let's trace the flow of changing a task's priority from a `TaskCard` .
1. **UI (`TaskCard.ts`)** : The user right-clicks the card and selects a new priority from the context menu.
2. **Event Handler** : The `onClick` handler for the menu item calls `plugin.updateTaskProperty(task, 'priority', newPriorityValue)` .
3. **Main Plugin (`main.ts`)** : The `updateTaskProperty` method is a convenience wrapper that calls `this.taskService.updateProperty(...)` .
4. **Service (`TaskService.ts`)** : The `updateProperty` method is executed.
a. It finds the `TFile` for the task.
b. It uses `app.fileManager.processFrontMatter()` to open the file and update the YAML. It uses the `fieldMapper` to get the correct property name (e.g., it might write `prio: high` instead of `priority: high` if the user configured it that way). It also updates the `dateModified` property.
2025-06-17 20:28:30 +00:00
c. **Native cache automatically updates** when the file is saved.
d. The minimal cache detects the native change and **coordinates view updates** .
5. **Event Coordination** :
* ** `MinimalNativeCache` **: Detects the native metadata change, updates essential indexes (if priority indexing was needed), and emits coordinated `EVENT_TASK_UPDATED` .
* **Views receive coordinated signal** : All views get a single, coordinated update event rather than multiple native events.
6. **View Updates** :
* ** `TaskListView.ts` **: The view's listener for `EVENT_TASK_UPDATED` fires. It fetches fresh task data from native cache and uses `updateTaskCard(element, updatedTask, ...)` to efficiently re-render just that one card.
* ** `AgendaView.ts` **: Its listener fires. Since a priority change might affect sorting, it triggers a `refresh()` , fetching fresh data directly from native cache and using the `DOMReconciler` to update the view.
* **Editor (`TaskLinkOverlay.ts`)** : The global listener in `main.ts` dispatches a `taskUpdateEffect` to all open editors. The `TaskLinkField` sees this effect and redraws any `TaskLinkWidget` s for the affected task path with fresh native cache data.
This entire flow happens almost instantaneously, with minimal cache coordination ensuring efficient updates while native cache provides always-fresh data.
### 5.3. When to Add an Index vs Compute On-Demand
**Add to Essential Indexes When**:
- The query is performance-critical (sub-100ms response needed)
- It's accessed very frequently (multiple times per second)
- The computation would involve scanning many files
- Examples: `tasksByDate` (calendar navigation), `tasksByStatus` (kanban boards)
**Compute On-Demand When**:
- The query is infrequent or user-initiated
- The dataset is small (< 1000 items )
- The computation is lightweight
- Examples: `getAllTags()` , `getTasksByPriority()` , `getAllContexts()`
**Decision Framework**:
```typescript
// Performance test: Is this query slow?
console.time('query');
const result = computeOnDemand();
console.timeEnd('query');
// If > 10ms and frequent -> consider indexing
// If < 10ms or infrequent - > keep on-demand
```
docs: Expand Tasknotes Development Guidelines with Performance Optimization and External Integration Best Practices
Summary:
• Added a new bullet under key architectural principles for "Obsidian Optimization Compliance" to indicate that the plugin follows Obsidian's load time optimization and deferred view compatibility best practices.
• Introduced a comprehensive "Performance Optimization & Obsidian Best Practices" section outlining strategies for keeping onload() lightweight, deferring heavy services until layout readiness, and dynamically importing heavy modules.
• Added detailed guidance on deferred view compatibility, including proper view initialization patterns and safe workspace iteration practices.
• Included a "File System Event Handling" subsection with patterns for registering vault events post-layout readiness, using debouncing, and ensuring event handlers do not interfere with startup performance.
• Added a new "External Data Integration" section describing the architecture for ICS calendar integration (both remote and local), file watcher patterns, and recommendations for integrating new external data sources with caching and UI configuration.
• Expanded error handling and data validation guidance to include safe date parsing with examples, optional property handling in interfaces, and developer best practices for type safety.
• Added a new "Testing & Quality Assurance" section with manual testing checklists and performance metrics to ensure robust plugin operation across different startup conditions and usage scenarios.
This update enhances the development guidelines by clearly documenting advanced performance strategies, integration patterns for external data sources, and comprehensive best practices for ensuring the plugin’s maintainability and compatibility with the latest Obsidian versions.
2025-06-16 11:20:49 +00:00
## 6. Performance Optimization & Obsidian Best Practices
### 6.1. Plugin Load Time Optimization
Following Obsidian's performance guidelines is crucial for user experience. The plugin implements several key optimizations:
**Load Time Pattern:**
```typescript
async onload() {
// Essential initialization only
await this.loadSettings();
this.initializeLightweightServices();
// Register view types and commands
this.registerViews();
this.addCommands();
// Defer expensive operations
this.app.workspace.onLayoutReady(() => {
this.initializeAfterLayoutReady();
});
}
private async initializeAfterLayoutReady() {
2025-06-17 20:28:30 +00:00
// Minimal cache initialization (lightweight)
this.cacheManager.initialize();
docs: Expand Tasknotes Development Guidelines with Performance Optimization and External Integration Best Practices
Summary:
• Added a new bullet under key architectural principles for "Obsidian Optimization Compliance" to indicate that the plugin follows Obsidian's load time optimization and deferred view compatibility best practices.
• Introduced a comprehensive "Performance Optimization & Obsidian Best Practices" section outlining strategies for keeping onload() lightweight, deferring heavy services until layout readiness, and dynamically importing heavy modules.
• Added detailed guidance on deferred view compatibility, including proper view initialization patterns and safe workspace iteration practices.
• Included a "File System Event Handling" subsection with patterns for registering vault events post-layout readiness, using debouncing, and ensuring event handlers do not interfere with startup performance.
• Added a new "External Data Integration" section describing the architecture for ICS calendar integration (both remote and local), file watcher patterns, and recommendations for integrating new external data sources with caching and UI configuration.
• Expanded error handling and data validation guidance to include safe date parsing with examples, optional property handling in interfaces, and developer best practices for type safety.
• Added a new "Testing & Quality Assurance" section with manual testing checklists and performance metrics to ensure robust plugin operation across different startup conditions and usage scenarios.
This update enhances the development guidelines by clearly documenting advanced performance strategies, integration patterns for external data sources, and comprehensive best practices for ensuring the plugin’s maintainability and compatibility with the latest Obsidian versions.
2025-06-16 11:20:49 +00:00
// Heavy service initialization
await this.pomodoroService.initialize();
// Editor services with async imports
const { TaskLinkDetectionService } = await import('./services/TaskLinkDetectionService');
}
```
**Developer Best Practices:**
* **Keep `onload()` lightweight** : Only include essential setup (settings, service constructors, view registration)
2025-06-17 20:28:30 +00:00
* **Defer expensive operations** : Move heavy service initialization to `onLayoutReady`
* **Use lazy index building** : Let minimal cache build essential indexes only when first accessed
docs: Expand Tasknotes Development Guidelines with Performance Optimization and External Integration Best Practices
Summary:
• Added a new bullet under key architectural principles for "Obsidian Optimization Compliance" to indicate that the plugin follows Obsidian's load time optimization and deferred view compatibility best practices.
• Introduced a comprehensive "Performance Optimization & Obsidian Best Practices" section outlining strategies for keeping onload() lightweight, deferring heavy services until layout readiness, and dynamically importing heavy modules.
• Added detailed guidance on deferred view compatibility, including proper view initialization patterns and safe workspace iteration practices.
• Included a "File System Event Handling" subsection with patterns for registering vault events post-layout readiness, using debouncing, and ensuring event handlers do not interfere with startup performance.
• Added a new "External Data Integration" section describing the architecture for ICS calendar integration (both remote and local), file watcher patterns, and recommendations for integrating new external data sources with caching and UI configuration.
• Expanded error handling and data validation guidance to include safe date parsing with examples, optional property handling in interfaces, and developer best practices for type safety.
• Added a new "Testing & Quality Assurance" section with manual testing checklists and performance metrics to ensure robust plugin operation across different startup conditions and usage scenarios.
This update enhances the development guidelines by clearly documenting advanced performance strategies, integration patterns for external data sources, and comprehensive best practices for ensuring the plugin’s maintainability and compatibility with the latest Obsidian versions.
2025-06-16 11:20:49 +00:00
* **Use async imports** : Load large services dynamically to reduce initial bundle size
* **Avoid vault events in constructors** : Register file watchers after layout is ready
2025-06-17 20:28:30 +00:00
### 6.2. Native Cache Integration Performance
The plugin maximizes Obsidian's native metadata cache performance:
**Efficient Native Access Pattern:**
```typescript
// Efficient: Direct native cache access
getTaskInfo(path: string): TaskInfo | null {
const file = this.app.vault.getAbstractFileByPath(path);
const metadata = this.app.metadataCache.getFileCache(file); // Already cached!
return this.extractTaskInfo(path, metadata.frontmatter);
}
// Efficient: Batch native operations
getAllTasksOfStatus(status: string): TaskInfo[] {
// Use essential index for paths
const taskPaths = this.minimalCache.getTaskPathsByStatus(status);
// Batch native cache access
return taskPaths.map(path => this.getTaskInfo(path)).filter(Boolean);
}
```
**Performance Guidelines:**
* **Trust native cache speed** : `getFileCache()` is already optimized by Obsidian
* **Use essential indexes for filtering** : Date and status indexes prevent full scans
* **Batch operations** : Process multiple files in single operations
* **Avoid redundant scanning** : Let minimal cache coordinate view updates
### 6.3. Memory Efficiency Through Minimal Indexing
**Memory Optimization Strategy:**
```typescript
// Minimal cache memory footprint
class MinimalNativeCache {
// Only 3 essential indexes (~70% reduction from previous approach)
private tasksByDate: Map< string , Set < string > > = new Map();
private tasksByStatus: Map< string , Set < string > > = new Map();
private overdueTasks: Set< string > = new Set();
// No redundant data storage - everything comes from native cache
getTaskInfo(path) {
return this.extractFromNativeCache(path); // Always fresh
}
}
```
**Memory Benefits:**
* **No duplicate data** : Task info comes directly from native cache
* **Minimal index storage** : Only path strings in essential indexes
* **Lazy computation** : Tags, contexts, priorities computed when needed
* **Automatic cleanup** : Native cache handles file lifecycle
### 6.4. Deferred View Compatibility
docs: Expand Tasknotes Development Guidelines with Performance Optimization and External Integration Best Practices
Summary:
• Added a new bullet under key architectural principles for "Obsidian Optimization Compliance" to indicate that the plugin follows Obsidian's load time optimization and deferred view compatibility best practices.
• Introduced a comprehensive "Performance Optimization & Obsidian Best Practices" section outlining strategies for keeping onload() lightweight, deferring heavy services until layout readiness, and dynamically importing heavy modules.
• Added detailed guidance on deferred view compatibility, including proper view initialization patterns and safe workspace iteration practices.
• Included a "File System Event Handling" subsection with patterns for registering vault events post-layout readiness, using debouncing, and ensuring event handlers do not interfere with startup performance.
• Added a new "External Data Integration" section describing the architecture for ICS calendar integration (both remote and local), file watcher patterns, and recommendations for integrating new external data sources with caching and UI configuration.
• Expanded error handling and data validation guidance to include safe date parsing with examples, optional property handling in interfaces, and developer best practices for type safety.
• Added a new "Testing & Quality Assurance" section with manual testing checklists and performance metrics to ensure robust plugin operation across different startup conditions and usage scenarios.
This update enhances the development guidelines by clearly documenting advanced performance strategies, integration patterns for external data sources, and comprehensive best practices for ensuring the plugin’s maintainability and compatibility with the latest Obsidian versions.
2025-06-16 11:20:49 +00:00
The plugin is compatible with Obsidian v1.7.2+ deferred views:
**View Implementation Pattern:**
```typescript
export class MyView extends ItemView {
constructor(leaf: WorkspaceLeaf, plugin: TaskNotesPlugin) {
super(leaf);
this.plugin = plugin;
// Lightweight constructor only
}
async onOpen() {
// Wait for plugin readiness
await this.plugin.onReady();
2025-06-17 20:28:30 +00:00
// Initialize view with native cache access
docs: Expand Tasknotes Development Guidelines with Performance Optimization and External Integration Best Practices
Summary:
• Added a new bullet under key architectural principles for "Obsidian Optimization Compliance" to indicate that the plugin follows Obsidian's load time optimization and deferred view compatibility best practices.
• Introduced a comprehensive "Performance Optimization & Obsidian Best Practices" section outlining strategies for keeping onload() lightweight, deferring heavy services until layout readiness, and dynamically importing heavy modules.
• Added detailed guidance on deferred view compatibility, including proper view initialization patterns and safe workspace iteration practices.
• Included a "File System Event Handling" subsection with patterns for registering vault events post-layout readiness, using debouncing, and ensuring event handlers do not interfere with startup performance.
• Added a new "External Data Integration" section describing the architecture for ICS calendar integration (both remote and local), file watcher patterns, and recommendations for integrating new external data sources with caching and UI configuration.
• Expanded error handling and data validation guidance to include safe date parsing with examples, optional property handling in interfaces, and developer best practices for type safety.
• Added a new "Testing & Quality Assurance" section with manual testing checklists and performance metrics to ensure robust plugin operation across different startup conditions and usage scenarios.
This update enhances the development guidelines by clearly documenting advanced performance strategies, integration patterns for external data sources, and comprehensive best practices for ensuring the plugin’s maintainability and compatibility with the latest Obsidian versions.
2025-06-16 11:20:49 +00:00
this.initializeView();
}
2025-06-17 20:28:30 +00:00
private async refreshData() {
// Direct native cache access for fresh data
const taskPaths = this.plugin.cacheManager.getTasksForDate(this.selectedDate);
const tasks = await Promise.all(
taskPaths.map(path => {
const file = this.app.vault.getAbstractFileByPath(path);
const metadata = this.app.metadataCache.getFileCache(file);
return this.extractTaskInfo(path, metadata.frontmatter);
})
);
this.renderTasks(tasks);
docs: Expand Tasknotes Development Guidelines with Performance Optimization and External Integration Best Practices
Summary:
• Added a new bullet under key architectural principles for "Obsidian Optimization Compliance" to indicate that the plugin follows Obsidian's load time optimization and deferred view compatibility best practices.
• Introduced a comprehensive "Performance Optimization & Obsidian Best Practices" section outlining strategies for keeping onload() lightweight, deferring heavy services until layout readiness, and dynamically importing heavy modules.
• Added detailed guidance on deferred view compatibility, including proper view initialization patterns and safe workspace iteration practices.
• Included a "File System Event Handling" subsection with patterns for registering vault events post-layout readiness, using debouncing, and ensuring event handlers do not interfere with startup performance.
• Added a new "External Data Integration" section describing the architecture for ICS calendar integration (both remote and local), file watcher patterns, and recommendations for integrating new external data sources with caching and UI configuration.
• Expanded error handling and data validation guidance to include safe date parsing with examples, optional property handling in interfaces, and developer best practices for type safety.
• Added a new "Testing & Quality Assurance" section with manual testing checklists and performance metrics to ensure robust plugin operation across different startup conditions and usage scenarios.
This update enhances the development guidelines by clearly documenting advanced performance strategies, integration patterns for external data sources, and comprehensive best practices for ensuring the plugin’s maintainability and compatibility with the latest Obsidian versions.
2025-06-16 11:20:49 +00:00
}
}
```
## 7. External Data Integration
### 7.1. ICS Calendar Integration Architecture
The plugin supports both remote ICS subscriptions and local ICS files through a unified service architecture:
**Service Structure:**
```typescript
interface ICSSubscription {
id: string;
name: string;
type: 'remote' | 'local';
url?: string; // For remote subscriptions
filePath?: string; // For local files
color: string;
enabled: boolean;
refreshInterval: number;
}
```
**Implementation Pattern:**
```typescript
async fetchSubscription(id: string): Promise< void > {
const subscription = this.getSubscription(id);
let icsData: string;
if (subscription.type === 'remote') {
icsData = await this.fetchRemoteICS(subscription.url);
} else {
icsData = await this.readLocalICS(subscription.filePath);
}
const events = this.parseICS(icsData);
this.updateCache(id, events);
}
```
### 7.2. File Watching for Local Resources
Local ICS files are automatically monitored for changes:
**File Watcher Pattern:**
```typescript
private startFileWatcher(subscription: ICSSubscription): void {
const modifyRef = this.plugin.app.vault.on('modify', (file) => {
if (file.path === subscription.filePath) {
// Debounce changes
setTimeout(() => this.refreshSubscription(subscription.id), 1000);
}
});
// Store cleanup function
this.fileWatchers.set(subscription.id, () => {
this.plugin.app.vault.offref(modifyRef);
});
}
```
**Developer Best Practices:**
* **Debounce file changes** : Prevent excessive refreshes on rapid file modifications
* **Store cleanup references** : Always provide proper cleanup in `destroy()` methods
* **Handle file deletion** : Gracefully handle cases where watched files are removed
* **Unified interface** : Keep local and remote data sources compatible through consistent interfaces
## 8. Error Handling & Data Validation
### 8.1. Date/Time Error Prevention
2025-08-02 12:54:11 +00:00
The plugin implements robust date parsing to handle various formats with UTC Anchor support:
docs: Expand Tasknotes Development Guidelines with Performance Optimization and External Integration Best Practices
Summary:
• Added a new bullet under key architectural principles for "Obsidian Optimization Compliance" to indicate that the plugin follows Obsidian's load time optimization and deferred view compatibility best practices.
• Introduced a comprehensive "Performance Optimization & Obsidian Best Practices" section outlining strategies for keeping onload() lightweight, deferring heavy services until layout readiness, and dynamically importing heavy modules.
• Added detailed guidance on deferred view compatibility, including proper view initialization patterns and safe workspace iteration practices.
• Included a "File System Event Handling" subsection with patterns for registering vault events post-layout readiness, using debouncing, and ensuring event handlers do not interfere with startup performance.
• Added a new "External Data Integration" section describing the architecture for ICS calendar integration (both remote and local), file watcher patterns, and recommendations for integrating new external data sources with caching and UI configuration.
• Expanded error handling and data validation guidance to include safe date parsing with examples, optional property handling in interfaces, and developer best practices for type safety.
• Added a new "Testing & Quality Assurance" section with manual testing checklists and performance metrics to ensure robust plugin operation across different startup conditions and usage scenarios.
This update enhances the development guidelines by clearly documenting advanced performance strategies, integration patterns for external data sources, and comprehensive best practices for ensuring the plugin’s maintainability and compatibility with the latest Obsidian versions.
2025-06-16 11:20:49 +00:00
**Safe Date Parsing Pattern:**
```typescript
// Always use dateUtils for parsing
2025-08-02 12:54:11 +00:00
import { parseDateToUTC, parseDateToLocal, validateDateInput, hasTimeComponent } from '../utils/dateUtils';
docs: Expand Tasknotes Development Guidelines with Performance Optimization and External Integration Best Practices
Summary:
• Added a new bullet under key architectural principles for "Obsidian Optimization Compliance" to indicate that the plugin follows Obsidian's load time optimization and deferred view compatibility best practices.
• Introduced a comprehensive "Performance Optimization & Obsidian Best Practices" section outlining strategies for keeping onload() lightweight, deferring heavy services until layout readiness, and dynamically importing heavy modules.
• Added detailed guidance on deferred view compatibility, including proper view initialization patterns and safe workspace iteration practices.
• Included a "File System Event Handling" subsection with patterns for registering vault events post-layout readiness, using debouncing, and ensuring event handlers do not interfere with startup performance.
• Added a new "External Data Integration" section describing the architecture for ICS calendar integration (both remote and local), file watcher patterns, and recommendations for integrating new external data sources with caching and UI configuration.
• Expanded error handling and data validation guidance to include safe date parsing with examples, optional property handling in interfaces, and developer best practices for type safety.
• Added a new "Testing & Quality Assurance" section with manual testing checklists and performance metrics to ensure robust plugin operation across different startup conditions and usage scenarios.
This update enhances the development guidelines by clearly documenting advanced performance strategies, integration patterns for external data sources, and comprehensive best practices for ensuring the plugin’s maintainability and compatibility with the latest Obsidian versions.
2025-06-16 11:20:49 +00:00
2025-08-02 12:54:11 +00:00
// Good - UTC Anchor approach
docs: Expand Tasknotes Development Guidelines with Performance Optimization and External Integration Best Practices
Summary:
• Added a new bullet under key architectural principles for "Obsidian Optimization Compliance" to indicate that the plugin follows Obsidian's load time optimization and deferred view compatibility best practices.
• Introduced a comprehensive "Performance Optimization & Obsidian Best Practices" section outlining strategies for keeping onload() lightweight, deferring heavy services until layout readiness, and dynamically importing heavy modules.
• Added detailed guidance on deferred view compatibility, including proper view initialization patterns and safe workspace iteration practices.
• Included a "File System Event Handling" subsection with patterns for registering vault events post-layout readiness, using debouncing, and ensuring event handlers do not interfere with startup performance.
• Added a new "External Data Integration" section describing the architecture for ICS calendar integration (both remote and local), file watcher patterns, and recommendations for integrating new external data sources with caching and UI configuration.
• Expanded error handling and data validation guidance to include safe date parsing with examples, optional property handling in interfaces, and developer best practices for type safety.
• Added a new "Testing & Quality Assurance" section with manual testing checklists and performance metrics to ensure robust plugin operation across different startup conditions and usage scenarios.
This update enhances the development guidelines by clearly documenting advanced performance strategies, integration patterns for external data sources, and comprehensive best practices for ensuring the plugin’s maintainability and compatibility with the latest Obsidian versions.
2025-06-16 11:20:49 +00:00
try {
2025-08-02 12:54:11 +00:00
if (hasTimeComponent(dateString)) {
// DateTime with explicit time - use local parsing
const dateTime = parseDateToLocal(dateString);
// Use for UI display
} else {
// Date-only - use UTC anchor
const date = parseDateToUTC(dateString);
// Use for internal logic, comparisons
}
docs: Expand Tasknotes Development Guidelines with Performance Optimization and External Integration Best Practices
Summary:
• Added a new bullet under key architectural principles for "Obsidian Optimization Compliance" to indicate that the plugin follows Obsidian's load time optimization and deferred view compatibility best practices.
• Introduced a comprehensive "Performance Optimization & Obsidian Best Practices" section outlining strategies for keeping onload() lightweight, deferring heavy services until layout readiness, and dynamically importing heavy modules.
• Added detailed guidance on deferred view compatibility, including proper view initialization patterns and safe workspace iteration practices.
• Included a "File System Event Handling" subsection with patterns for registering vault events post-layout readiness, using debouncing, and ensuring event handlers do not interfere with startup performance.
• Added a new "External Data Integration" section describing the architecture for ICS calendar integration (both remote and local), file watcher patterns, and recommendations for integrating new external data sources with caching and UI configuration.
• Expanded error handling and data validation guidance to include safe date parsing with examples, optional property handling in interfaces, and developer best practices for type safety.
• Added a new "Testing & Quality Assurance" section with manual testing checklists and performance metrics to ensure robust plugin operation across different startup conditions and usage scenarios.
This update enhances the development guidelines by clearly documenting advanced performance strategies, integration patterns for external data sources, and comprehensive best practices for ensuring the plugin’s maintainability and compatibility with the latest Obsidian versions.
2025-06-16 11:20:49 +00:00
} catch (error) {
// Handle invalid date
}
// Bad - Direct Date constructor
const date = new Date(dateString); // May create unexpected results
2025-08-02 12:54:11 +00:00
// Bad - Using deprecated parseDate
const date = parseDate(dateString); // Use parseDateToUTC or parseDateToLocal instead
docs: Expand Tasknotes Development Guidelines with Performance Optimization and External Integration Best Practices
Summary:
• Added a new bullet under key architectural principles for "Obsidian Optimization Compliance" to indicate that the plugin follows Obsidian's load time optimization and deferred view compatibility best practices.
• Introduced a comprehensive "Performance Optimization & Obsidian Best Practices" section outlining strategies for keeping onload() lightweight, deferring heavy services until layout readiness, and dynamically importing heavy modules.
• Added detailed guidance on deferred view compatibility, including proper view initialization patterns and safe workspace iteration practices.
• Included a "File System Event Handling" subsection with patterns for registering vault events post-layout readiness, using debouncing, and ensuring event handlers do not interfere with startup performance.
• Added a new "External Data Integration" section describing the architecture for ICS calendar integration (both remote and local), file watcher patterns, and recommendations for integrating new external data sources with caching and UI configuration.
• Expanded error handling and data validation guidance to include safe date parsing with examples, optional property handling in interfaces, and developer best practices for type safety.
• Added a new "Testing & Quality Assurance" section with manual testing checklists and performance metrics to ensure robust plugin operation across different startup conditions and usage scenarios.
This update enhances the development guidelines by clearly documenting advanced performance strategies, integration patterns for external data sources, and comprehensive best practices for ensuring the plugin’s maintainability and compatibility with the latest Obsidian versions.
2025-06-16 11:20:49 +00:00
```
**Supported Date Formats:**
* ISO datetime: `2025-02-23T20:28:49`
* Space-separated: `2025-02-23 20:28:49`
2025-08-02 12:54:11 +00:00
* Date-only: `2025-02-23` (UTC anchored internally)
docs: Expand Tasknotes Development Guidelines with Performance Optimization and External Integration Best Practices
Summary:
• Added a new bullet under key architectural principles for "Obsidian Optimization Compliance" to indicate that the plugin follows Obsidian's load time optimization and deferred view compatibility best practices.
• Introduced a comprehensive "Performance Optimization & Obsidian Best Practices" section outlining strategies for keeping onload() lightweight, deferring heavy services until layout readiness, and dynamically importing heavy modules.
• Added detailed guidance on deferred view compatibility, including proper view initialization patterns and safe workspace iteration practices.
• Included a "File System Event Handling" subsection with patterns for registering vault events post-layout readiness, using debouncing, and ensuring event handlers do not interfere with startup performance.
• Added a new "External Data Integration" section describing the architecture for ICS calendar integration (both remote and local), file watcher patterns, and recommendations for integrating new external data sources with caching and UI configuration.
• Expanded error handling and data validation guidance to include safe date parsing with examples, optional property handling in interfaces, and developer best practices for type safety.
• Added a new "Testing & Quality Assurance" section with manual testing checklists and performance metrics to ensure robust plugin operation across different startup conditions and usage scenarios.
This update enhances the development guidelines by clearly documenting advanced performance strategies, integration patterns for external data sources, and comprehensive best practices for ensuring the plugin’s maintainability and compatibility with the latest Obsidian versions.
2025-06-16 11:20:49 +00:00
* ISO week: `2025-W02`
2025-08-02 12:54:11 +00:00
* Timezone-aware: `2025-02-23T20:28:49-05:00`
**Common Pitfalls to Avoid:**
```typescript
// WRONG: Direct date construction varies by timezone
const date = new Date('2025-08-01'); // Different results in Tokyo vs LA
// RIGHT: UTC anchor ensures consistency
const date = parseDateToUTC('2025-08-01'); // Same result everywhere
// WRONG: Mixing parsing methods
const date1 = new Date(task.due);
const date2 = parseDate(task.scheduled);
// RIGHT: Consistent parsing approach
const date1 = parseDateToUTC(task.due);
const date2 = parseDateToUTC(task.scheduled);
```
docs: Expand Tasknotes Development Guidelines with Performance Optimization and External Integration Best Practices
Summary:
• Added a new bullet under key architectural principles for "Obsidian Optimization Compliance" to indicate that the plugin follows Obsidian's load time optimization and deferred view compatibility best practices.
• Introduced a comprehensive "Performance Optimization & Obsidian Best Practices" section outlining strategies for keeping onload() lightweight, deferring heavy services until layout readiness, and dynamically importing heavy modules.
• Added detailed guidance on deferred view compatibility, including proper view initialization patterns and safe workspace iteration practices.
• Included a "File System Event Handling" subsection with patterns for registering vault events post-layout readiness, using debouncing, and ensuring event handlers do not interfere with startup performance.
• Added a new "External Data Integration" section describing the architecture for ICS calendar integration (both remote and local), file watcher patterns, and recommendations for integrating new external data sources with caching and UI configuration.
• Expanded error handling and data validation guidance to include safe date parsing with examples, optional property handling in interfaces, and developer best practices for type safety.
• Added a new "Testing & Quality Assurance" section with manual testing checklists and performance metrics to ensure robust plugin operation across different startup conditions and usage scenarios.
This update enhances the development guidelines by clearly documenting advanced performance strategies, integration patterns for external data sources, and comprehensive best practices for ensuring the plugin’s maintainability and compatibility with the latest Obsidian versions.
2025-06-16 11:20:49 +00:00
### 8.2. Type Safety & Validation
**Interface Extension Pattern:**
```typescript
// When adding new optional properties
interface TaskInfo {
// ... existing properties
newProperty?: string; // Always optional for backward compatibility
}
// Provide defaults in service layer
const taskWithDefaults = {
...existingTask,
newProperty: existingTask.newProperty || defaultValue
};
```
**Developer Best Practices:**
* **Make new properties optional** : Ensures backward compatibility
* **Validate external data** : Always validate data from external sources
* **Provide meaningful errors** : Help users understand what went wrong
* **Graceful degradation** : Continue functioning when optional features fail
## 9. Testing & Quality Assurance
### 9.1. Manual Testing Checklist
When implementing new features, test these scenarios:
**Plugin Load Testing:**
* [ ] Clean Obsidian startup (no existing plugin data)
* [ ] Startup with existing plugin data
* [ ] Startup with large vaults (1000+ files)
* [ ] Hot reload during development
**View Testing:**
* [ ] View opens correctly when deferred
2025-06-17 20:28:30 +00:00
* [ ] View responds to coordinated data changes
docs: Expand Tasknotes Development Guidelines with Performance Optimization and External Integration Best Practices
Summary:
• Added a new bullet under key architectural principles for "Obsidian Optimization Compliance" to indicate that the plugin follows Obsidian's load time optimization and deferred view compatibility best practices.
• Introduced a comprehensive "Performance Optimization & Obsidian Best Practices" section outlining strategies for keeping onload() lightweight, deferring heavy services until layout readiness, and dynamically importing heavy modules.
• Added detailed guidance on deferred view compatibility, including proper view initialization patterns and safe workspace iteration practices.
• Included a "File System Event Handling" subsection with patterns for registering vault events post-layout readiness, using debouncing, and ensuring event handlers do not interfere with startup performance.
• Added a new "External Data Integration" section describing the architecture for ICS calendar integration (both remote and local), file watcher patterns, and recommendations for integrating new external data sources with caching and UI configuration.
• Expanded error handling and data validation guidance to include safe date parsing with examples, optional property handling in interfaces, and developer best practices for type safety.
• Added a new "Testing & Quality Assurance" section with manual testing checklists and performance metrics to ensure robust plugin operation across different startup conditions and usage scenarios.
This update enhances the development guidelines by clearly documenting advanced performance strategies, integration patterns for external data sources, and comprehensive best practices for ensuring the plugin’s maintainability and compatibility with the latest Obsidian versions.
2025-06-16 11:20:49 +00:00
* [ ] View handles no data gracefully
* [ ] View cleanup on close
2025-06-17 20:28:30 +00:00
**Cache Coordination Testing:**
* [ ] Multiple views update efficiently on file changes
* [ ] Essential indexes remain consistent
* [ ] Native cache integration works correctly
* [ ] Memory usage remains minimal
docs: Expand Tasknotes Development Guidelines with Performance Optimization and External Integration Best Practices
Summary:
• Added a new bullet under key architectural principles for "Obsidian Optimization Compliance" to indicate that the plugin follows Obsidian's load time optimization and deferred view compatibility best practices.
• Introduced a comprehensive "Performance Optimization & Obsidian Best Practices" section outlining strategies for keeping onload() lightweight, deferring heavy services until layout readiness, and dynamically importing heavy modules.
• Added detailed guidance on deferred view compatibility, including proper view initialization patterns and safe workspace iteration practices.
• Included a "File System Event Handling" subsection with patterns for registering vault events post-layout readiness, using debouncing, and ensuring event handlers do not interfere with startup performance.
• Added a new "External Data Integration" section describing the architecture for ICS calendar integration (both remote and local), file watcher patterns, and recommendations for integrating new external data sources with caching and UI configuration.
• Expanded error handling and data validation guidance to include safe date parsing with examples, optional property handling in interfaces, and developer best practices for type safety.
• Added a new "Testing & Quality Assurance" section with manual testing checklists and performance metrics to ensure robust plugin operation across different startup conditions and usage scenarios.
This update enhances the development guidelines by clearly documenting advanced performance strategies, integration patterns for external data sources, and comprehensive best practices for ensuring the plugin’s maintainability and compatibility with the latest Obsidian versions.
2025-06-16 11:20:49 +00:00
### 9.2. Performance Testing
**Load Time Metrics:**
2025-06-17 20:28:30 +00:00
* Plugin should add < 50ms to Obsidian startup ( improved with minimal cache )
docs: Expand Tasknotes Development Guidelines with Performance Optimization and External Integration Best Practices
Summary:
• Added a new bullet under key architectural principles for "Obsidian Optimization Compliance" to indicate that the plugin follows Obsidian's load time optimization and deferred view compatibility best practices.
• Introduced a comprehensive "Performance Optimization & Obsidian Best Practices" section outlining strategies for keeping onload() lightweight, deferring heavy services until layout readiness, and dynamically importing heavy modules.
• Added detailed guidance on deferred view compatibility, including proper view initialization patterns and safe workspace iteration practices.
• Included a "File System Event Handling" subsection with patterns for registering vault events post-layout readiness, using debouncing, and ensuring event handlers do not interfere with startup performance.
• Added a new "External Data Integration" section describing the architecture for ICS calendar integration (both remote and local), file watcher patterns, and recommendations for integrating new external data sources with caching and UI configuration.
• Expanded error handling and data validation guidance to include safe date parsing with examples, optional property handling in interfaces, and developer best practices for type safety.
• Added a new "Testing & Quality Assurance" section with manual testing checklists and performance metrics to ensure robust plugin operation across different startup conditions and usage scenarios.
This update enhances the development guidelines by clearly documenting advanced performance strategies, integration patterns for external data sources, and comprehensive best practices for ensuring the plugin’s maintainability and compatibility with the latest Obsidian versions.
2025-06-16 11:20:49 +00:00
* Views should render within 200ms of opening
* File operations should not block UI
**Memory Usage:**
2025-06-17 20:28:30 +00:00
* Monitor minimal cache index sizes
docs: Expand Tasknotes Development Guidelines with Performance Optimization and External Integration Best Practices
Summary:
• Added a new bullet under key architectural principles for "Obsidian Optimization Compliance" to indicate that the plugin follows Obsidian's load time optimization and deferred view compatibility best practices.
• Introduced a comprehensive "Performance Optimization & Obsidian Best Practices" section outlining strategies for keeping onload() lightweight, deferring heavy services until layout readiness, and dynamically importing heavy modules.
• Added detailed guidance on deferred view compatibility, including proper view initialization patterns and safe workspace iteration practices.
• Included a "File System Event Handling" subsection with patterns for registering vault events post-layout readiness, using debouncing, and ensuring event handlers do not interfere with startup performance.
• Added a new "External Data Integration" section describing the architecture for ICS calendar integration (both remote and local), file watcher patterns, and recommendations for integrating new external data sources with caching and UI configuration.
• Expanded error handling and data validation guidance to include safe date parsing with examples, optional property handling in interfaces, and developer best practices for type safety.
• Added a new "Testing & Quality Assurance" section with manual testing checklists and performance metrics to ensure robust plugin operation across different startup conditions and usage scenarios.
This update enhances the development guidelines by clearly documenting advanced performance strategies, integration patterns for external data sources, and comprehensive best practices for ensuring the plugin’s maintainability and compatibility with the latest Obsidian versions.
2025-06-16 11:20:49 +00:00
* Ensure proper cleanup of event listeners
2025-06-17 20:28:30 +00:00
* Verify no memory leaks in long-running sessions
* Check that native cache integration doesn't duplicate data
**Coordination Efficiency:**
* Single file change should trigger one coordinated update cycle
* Multiple rapid changes should be batched efficiently
* View updates should not redundantly scan files
docs: Expand Tasknotes Development Guidelines with Performance Optimization and External Integration Best Practices
Summary:
• Added a new bullet under key architectural principles for "Obsidian Optimization Compliance" to indicate that the plugin follows Obsidian's load time optimization and deferred view compatibility best practices.
• Introduced a comprehensive "Performance Optimization & Obsidian Best Practices" section outlining strategies for keeping onload() lightweight, deferring heavy services until layout readiness, and dynamically importing heavy modules.
• Added detailed guidance on deferred view compatibility, including proper view initialization patterns and safe workspace iteration practices.
• Included a "File System Event Handling" subsection with patterns for registering vault events post-layout readiness, using debouncing, and ensuring event handlers do not interfere with startup performance.
• Added a new "External Data Integration" section describing the architecture for ICS calendar integration (both remote and local), file watcher patterns, and recommendations for integrating new external data sources with caching and UI configuration.
• Expanded error handling and data validation guidance to include safe date parsing with examples, optional property handling in interfaces, and developer best practices for type safety.
• Added a new "Testing & Quality Assurance" section with manual testing checklists and performance metrics to ensure robust plugin operation across different startup conditions and usage scenarios.
This update enhances the development guidelines by clearly documenting advanced performance strategies, integration patterns for external data sources, and comprehensive best practices for ensuring the plugin’s maintainability and compatibility with the latest Obsidian versions.
2025-06-16 11:20:49 +00:00
2025-08-02 12:54:11 +00:00
This streamlined architecture ensures the plugin remains performant, maintainable, and maximally leverages Obsidian's native capabilities while providing intelligent coordination for optimal view performance.
## 10. Quick Reference: UTC Anchor Date Handling
### When to Use Each Function
| Function | Use Case | Example |
|----------|----------|---------|
| `parseDateToUTC()` | Internal logic, comparisons, sorting | `const date = parseDateToUTC('2025-08-01')` |
| `parseDateToLocal()` | UI display, user input | `const date = parseDateToLocal('2025-08-01')` |
| `hasTimeComponent()` | Check if string has time | `if (hasTimeComponent(str)) { ... }` |
| `isBeforeDateSafe()` | Compare date-only strings | `if (isBeforeDateSafe(date1, date2)) { ... }` |
| `isSameDateSafe()` | Check if same calendar day | `if (isSameDateSafe(date1, date2)) { ... }` |
| `isOverdueTimeAware()` | Check if task is overdue | `if (isOverdueTimeAware(task.due)) { ... }` |
| `formatDateForStorage()` | Save to YAML/storage | `const stored = formatDateForStorage(date)` |
| `getCurrentTimestamp()` | Create timestamps | `task.dateModified = getCurrentTimestamp()` |
### Common Patterns
```typescript
// Pattern 1: Processing task dates for logic
const tasks = allTasks
.map(task => ({
...task,
dueDate: task.due ? parseDateToUTC(task.due) : null
}))
.sort((a, b) => a.dueDate.getTime() - b.dueDate.getTime());
// Pattern 2: Displaying dates to users
const displayDate = hasTimeComponent(task.due)
? format(parseDateToLocal(task.due), 'MMM d, h:mm a')
: format(parseDateToLocal(task.due), 'MMM d');
// Pattern 3: Filtering by date
const todayTasks = tasks.filter(task =>
task.due & & isSameDateSafe(task.due, getTodayString())
);
// Pattern 4: Consistent date storage
const updatedTask = {
...task,
due: formatDateForStorage(selectedDate),
dateModified: getCurrentTimestamp()
};
```
### Do's and Don'ts
**DO:**
- ✅ Use `parseDateToUTC()` for all internal logic
- ✅ Use `parseDateToLocal()` for UI display
- ✅ Check `hasTimeComponent()` when handling mixed date types
- ✅ Use safe comparison functions
- ✅ Store dates in YYYY-MM-DD format
**DON'T:**
- ❌ Use `new Date(dateString)` directly
- ❌ Use deprecated `parseDate()` function
- ❌ Mix parsing methods in the same logic flow
- ❌ Assume timezone behavior without testing
- ❌ Compare Date objects from different parsing methods