mirror of
https://github.com/taskgenius/taskgenius-plugin.git
synced 2026-07-22 06:40:25 +00:00
refactor(dataflow): consolidate time parsing types and remove debug files
- Remove temporary debug files (debug-actual-parsing.js, debug-task-parsing.js, debug-time-parsing.js) - Move time parsing type definitions from task.d.ts to dedicated time-parsing.ts - Update all tests and services to import from new type location - Simplify BaseTask interface by extracting time-related properties - Minor CSS adjustments for timeline sidebar and main styles
This commit is contained in:
parent
dc364df963
commit
13bd8f3b05
18 changed files with 185 additions and 427 deletions
|
|
@ -1,195 +0,0 @@
|
|||
// Debug script to simulate the actual task parsing process
|
||||
console.log("=== Simulating Task Parsing Process ===");
|
||||
|
||||
// Simulate the task content
|
||||
const taskContent = "12:00-13:00 New 任务 #project/任务 🔼 📅 2025-06-19";
|
||||
console.log("Task content:", taskContent);
|
||||
|
||||
// Simulate the time parsing service configuration (from DEFAULT_SETTINGS)
|
||||
const timeParsingConfig = {
|
||||
enabled: true,
|
||||
supportedLanguages: ["en", "zh"],
|
||||
dateKeywords: {
|
||||
start: ["start", "begin", "from", "starting", "begins", "开始", "从", "起始", "起", "始于", "自"],
|
||||
due: ["due", "deadline", "by", "until", "before", "expires", "ends", "截止", "到期", "之前", "期限", "最晚", "结束", "终止", "完成于"],
|
||||
scheduled: ["scheduled", "on", "at", "planned", "set for", "arranged", "安排", "计划", "在", "定于", "预定", "约定", "设定"]
|
||||
},
|
||||
removeOriginalText: true,
|
||||
perLineProcessing: true,
|
||||
realTimeReplacement: true,
|
||||
timePatterns: {
|
||||
singleTime: [
|
||||
/\b([01]?\d|2[0-3]):([0-5]\d)(?::([0-5]\d))?\b/g,
|
||||
/\b(1[0-2]|0?[1-9]):([0-5]\d)(?::([0-5]\d))?\s*(AM|PM|am|pm)\b/g
|
||||
],
|
||||
timeRange: [
|
||||
/\b([01]?\d|2[0-3]):([0-5]\d)(?::([0-5]\d))?\s*[-~~]\s*([01]?\d|2[0-3]):([0-5]\d)(?::([0-5]\d))?\b/g,
|
||||
/\b(1[0-2]|0?[1-9]):([0-5]\d)(?::([0-5]\d))?\s*(AM|PM|am|pm)?\s*[-~~]\s*(1[0-2]|0?[1-9]):([0-5]\d)(?::([0-5]\d))?\s*(AM|PM|am|pm)\b/g
|
||||
],
|
||||
rangeSeparators: ["-", "~", "~"]
|
||||
},
|
||||
timeDefaults: {
|
||||
preferredFormat: "24h",
|
||||
defaultPeriod: "AM",
|
||||
midnightCrossing: "next-day"
|
||||
}
|
||||
};
|
||||
|
||||
console.log("\n=== Time Parsing Configuration ===");
|
||||
console.log("Enabled:", timeParsingConfig.enabled);
|
||||
console.log("Range separators:", timeParsingConfig.timePatterns.rangeSeparators);
|
||||
|
||||
// Test the time range regex from the config
|
||||
console.log("\n=== Testing Time Range Regex from Config ===");
|
||||
const timeRangeRegex = timeParsingConfig.timePatterns.timeRange[0];
|
||||
console.log("Regex:", timeRangeRegex);
|
||||
|
||||
const matches = [...taskContent.matchAll(timeRangeRegex)];
|
||||
console.log("Matches found:", matches.length);
|
||||
matches.forEach((match, index) => {
|
||||
console.log(`Match ${index}:`, {
|
||||
fullMatch: match[0],
|
||||
position: match.index,
|
||||
groups: match.slice(1)
|
||||
});
|
||||
});
|
||||
|
||||
// Simulate the parseTimeComponent function
|
||||
function parseTimeComponent(timeText) {
|
||||
const cleanedText = timeText.trim();
|
||||
|
||||
// Try 24-hour format
|
||||
const match24h = cleanedText.match(/^([01]?\d|2[0-3]):([0-5]\d)(?::([0-5]\d))?$/);
|
||||
if (match24h) {
|
||||
const hour = parseInt(match24h[1], 10);
|
||||
const minute = parseInt(match24h[2], 10);
|
||||
const second = match24h[3] ? parseInt(match24h[3], 10) : undefined;
|
||||
|
||||
return {
|
||||
hour,
|
||||
minute,
|
||||
second,
|
||||
originalText: cleanedText,
|
||||
isRange: false,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Simulate the extractTimeComponents function
|
||||
function extractTimeComponents(text) {
|
||||
const timeComponents = {};
|
||||
const timeExpressions = [];
|
||||
|
||||
// Check for time ranges first
|
||||
const rangeMatches = [...text.matchAll(timeRangeRegex)];
|
||||
|
||||
for (const match of rangeMatches) {
|
||||
const fullMatch = match[0];
|
||||
const index = match.index || 0;
|
||||
|
||||
// Parse start and end times
|
||||
const parts = fullMatch.split(/\s*[-~\uff5e]\s*/);
|
||||
if (parts.length === 2) {
|
||||
const startTime = parseTimeComponent(parts[0]);
|
||||
const endTime = parseTimeComponent(parts[1]);
|
||||
|
||||
if (startTime && endTime) {
|
||||
startTime.isRange = true;
|
||||
endTime.isRange = true;
|
||||
startTime.rangePartner = endTime;
|
||||
endTime.rangePartner = startTime;
|
||||
|
||||
timeExpressions.push({
|
||||
text: fullMatch,
|
||||
index,
|
||||
isRange: true,
|
||||
rangeStart: startTime,
|
||||
rangeEnd: endTime,
|
||||
});
|
||||
|
||||
// Determine context for time range
|
||||
const context = determineTimeContext(text, fullMatch, index);
|
||||
console.log("Determined context:", context);
|
||||
|
||||
if (context === "start" || !timeComponents.startTime) {
|
||||
timeComponents.startTime = startTime;
|
||||
timeComponents.endTime = endTime;
|
||||
} else if (context === "due") {
|
||||
timeComponents.dueTime = startTime;
|
||||
// For due time ranges, we might want to use the end time as the actual due time
|
||||
// But for now, let's keep it as start time for consistency
|
||||
} else if (context === "scheduled") {
|
||||
timeComponents.scheduledTime = startTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { timeComponents, timeExpressions };
|
||||
}
|
||||
|
||||
// Simulate the determineTimeContext function
|
||||
function determineTimeContext(text, expression, index) {
|
||||
const beforeText = text.substring(Math.max(0, index - 20), index).toLowerCase();
|
||||
const afterText = text.substring(index + expression.length, Math.min(text.length, index + expression.length + 20)).toLowerCase();
|
||||
const context = beforeText + " " + afterText;
|
||||
|
||||
// Check for start keywords first
|
||||
for (const keyword of timeParsingConfig.dateKeywords.start) {
|
||||
if (context.includes(keyword.toLowerCase())) {
|
||||
return "start";
|
||||
}
|
||||
}
|
||||
|
||||
// Check for scheduled keywords
|
||||
for (const keyword of timeParsingConfig.dateKeywords.scheduled) {
|
||||
if (context.includes(keyword.toLowerCase())) {
|
||||
return "scheduled";
|
||||
}
|
||||
}
|
||||
|
||||
// Check for due keywords
|
||||
for (const keyword of timeParsingConfig.dateKeywords.due) {
|
||||
if (context.includes(keyword.toLowerCase())) {
|
||||
return "due";
|
||||
}
|
||||
}
|
||||
|
||||
// Default based on common patterns
|
||||
if (context.includes("at") || context.includes("@")) {
|
||||
return "scheduled";
|
||||
}
|
||||
|
||||
// Default to due if no specific context found
|
||||
return "due";
|
||||
}
|
||||
|
||||
console.log("\n=== Simulating extractTimeComponents ===");
|
||||
const result = extractTimeComponents(taskContent);
|
||||
|
||||
// Handle circular references by creating a safe representation
|
||||
function safeStringify(obj) {
|
||||
const seen = new WeakSet();
|
||||
return JSON.stringify(obj, (key, val) => {
|
||||
if (val != null && typeof val == "object") {
|
||||
if (seen.has(val)) {
|
||||
return "[Circular]";
|
||||
}
|
||||
seen.add(val);
|
||||
}
|
||||
return val;
|
||||
}, 2);
|
||||
}
|
||||
|
||||
console.log("Time components:", safeStringify(result.timeComponents));
|
||||
console.log("Time expressions:", safeStringify(result.timeExpressions));
|
||||
|
||||
// Check what should be in the task metadata
|
||||
console.log("\n=== Expected Task Metadata ===");
|
||||
if (Object.keys(result.timeComponents).length > 0) {
|
||||
console.log("Should have timeComponents:", result.timeComponents);
|
||||
console.log("Should have enhancedDates (if combined with date)");
|
||||
} else {
|
||||
console.log("No time components found - this is the problem!");
|
||||
}
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
// Debug script to test task parsing with time components
|
||||
const taskContent = "12:00-13:00 New 任务 #project/任务 🔼 📅 2025-06-19";
|
||||
|
||||
console.log("Testing task content:", taskContent);
|
||||
|
||||
// Test the time parsing service patterns
|
||||
const TIME_RANGE = /\b([01]?\d|2[0-3]):([0-5]\d)(?::([0-5]\d))?\s*[-~~]\s*([01]?\d|2[0-3]):([0-5]\d)(?::([0-5]\d))?\b/g;
|
||||
|
||||
console.log("\n=== Time Range Pattern Test ===");
|
||||
const rangeMatches = [...taskContent.matchAll(TIME_RANGE)];
|
||||
console.log("Range matches found:", rangeMatches.length);
|
||||
rangeMatches.forEach((match, index) => {
|
||||
console.log(`Range Match ${index}:`, {
|
||||
fullMatch: match[0],
|
||||
position: match.index,
|
||||
startHour: match[1],
|
||||
startMinute: match[2],
|
||||
endHour: match[4],
|
||||
endMinute: match[5]
|
||||
});
|
||||
});
|
||||
|
||||
// Test context determination
|
||||
const beforeText = taskContent.substring(Math.max(0, 0 - 20), 0).toLowerCase();
|
||||
const afterText = taskContent.substring(0 + "12:00-13:00".length, Math.min(taskContent.length, 0 + "12:00-13:00".length + 20)).toLowerCase();
|
||||
const context = beforeText + " " + afterText;
|
||||
|
||||
console.log("\n=== Context Analysis ===");
|
||||
console.log("Before text:", beforeText);
|
||||
console.log("After text:", afterText);
|
||||
console.log("Combined context:", context);
|
||||
|
||||
// Test date keywords
|
||||
const dateKeywords = {
|
||||
start: ["start", "from", "begin", "开始"],
|
||||
due: ["due", "deadline", "by", "截止", "到期"],
|
||||
scheduled: ["at", "on", "scheduled", "安排", "@"]
|
||||
};
|
||||
|
||||
console.log("\n=== Keyword Detection ===");
|
||||
for (const [type, keywords] of Object.entries(dateKeywords)) {
|
||||
const found = keywords.some(keyword => context.includes(keyword.toLowerCase()));
|
||||
console.log(`${type}: ${found} (keywords: ${keywords.join(', ')})`);
|
||||
}
|
||||
|
||||
// Test if the time range would be detected as "due" (default)
|
||||
console.log("\nExpected context type: due (default)");
|
||||
|
||||
// Test individual time parsing
|
||||
function parseTimeComponent(timeText) {
|
||||
const cleanedText = timeText.trim();
|
||||
|
||||
// Try 24-hour format
|
||||
const match24h = cleanedText.match(/^([01]?\d|2[0-3]):([0-5]\d)(?::([0-5]\d))?$/);
|
||||
if (match24h) {
|
||||
const hour = parseInt(match24h[1], 10);
|
||||
const minute = parseInt(match24h[2], 10);
|
||||
const second = match24h[3] ? parseInt(match24h[3], 10) : undefined;
|
||||
|
||||
return {
|
||||
hour,
|
||||
minute,
|
||||
second,
|
||||
originalText: cleanedText,
|
||||
isRange: false,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
console.log("\n=== Individual Time Component Parsing ===");
|
||||
const startTime = parseTimeComponent("12:00");
|
||||
const endTime = parseTimeComponent("13:00");
|
||||
|
||||
console.log("Start time component:", startTime);
|
||||
console.log("End time component:", endTime);
|
||||
|
||||
if (startTime && endTime) {
|
||||
startTime.isRange = true;
|
||||
endTime.isRange = true;
|
||||
startTime.rangePartner = endTime;
|
||||
endTime.rangePartner = startTime;
|
||||
|
||||
console.log("Range setup complete:");
|
||||
console.log("Start time with range:", startTime);
|
||||
console.log("End time with range:", endTime);
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
// Debug script to test time parsing
|
||||
const testText = "12:00-13:00 New 任务 #project/任务 🔼 📅 2025-06-19";
|
||||
|
||||
// Test the regex patterns
|
||||
const TIME_RANGE = /\b([01]?\d|2[0-3]):([0-5]\d)(?::([0-5]\d))?\s*[-~~]\s*([01]?\d|2[0-3]):([0-5]\d)(?::([0-5]\d))?\b/g;
|
||||
|
||||
console.log("Testing time range regex:");
|
||||
console.log("Text:", testText);
|
||||
console.log("Regex:", TIME_RANGE);
|
||||
|
||||
const matches = [...testText.matchAll(TIME_RANGE)];
|
||||
console.log("Matches found:", matches.length);
|
||||
matches.forEach((match, index) => {
|
||||
console.log(`Match ${index}:`, match[0], "at position", match.index);
|
||||
});
|
||||
|
||||
// Test individual time parsing
|
||||
const timeText = "12:00";
|
||||
const TIME_24H = /^([01]?\d|2[0-3]):([0-5]\d)(?::([0-5]\d))?$/;
|
||||
console.log("\nTesting individual time parsing:");
|
||||
console.log("Time text:", timeText);
|
||||
console.log("24h regex match:", timeText.match(TIME_24H));
|
||||
|
|
@ -180,6 +180,11 @@ describe("Enhanced Time Parsing Edge Cases", () => {
|
|||
test("should respect configuration for ambiguous time handling", () => {
|
||||
const config: EnhancedTimeParsingConfig = {
|
||||
...DEFAULT_TIME_PARSING_CONFIG,
|
||||
timePatterns: {
|
||||
singleTime: [/\d{1,2}:\d{2}(?::\d{2})?(?:\s*(?:AM|PM|am|pm))?/],
|
||||
timeRange: [/\d{1,2}:\d{2}(?:\s*(?:AM|PM|am|pm))?\s*[-–—~]\s*\d{1,2}:\d{2}(?:\s*(?:AM|PM|am|pm))?/],
|
||||
rangeSeparators: ["-", "–", "—", "~"],
|
||||
},
|
||||
timeDefaults: {
|
||||
preferredFormat: "12h",
|
||||
defaultPeriod: "PM",
|
||||
|
|
@ -382,6 +387,11 @@ describe("Enhanced Time Parsing Edge Cases", () => {
|
|||
test("should respect midnight crossing configuration", () => {
|
||||
const nextDayConfig: EnhancedTimeParsingConfig = {
|
||||
...DEFAULT_TIME_PARSING_CONFIG,
|
||||
timePatterns: {
|
||||
singleTime: [/\d{1,2}:\d{2}(?::\d{2})?(?:\s*(?:AM|PM|am|pm))?/],
|
||||
timeRange: [/\d{1,2}:\d{2}(?:\s*(?:AM|PM|am|pm))?\s*[-–—~]\s*\d{1,2}:\d{2}(?:\s*(?:AM|PM|am|pm))?/],
|
||||
rangeSeparators: ["-", "–", "—", "~"],
|
||||
},
|
||||
timeDefaults: {
|
||||
preferredFormat: "24h",
|
||||
defaultPeriod: "PM",
|
||||
|
|
@ -391,6 +401,11 @@ describe("Enhanced Time Parsing Edge Cases", () => {
|
|||
|
||||
const sameDayConfig: EnhancedTimeParsingConfig = {
|
||||
...DEFAULT_TIME_PARSING_CONFIG,
|
||||
timePatterns: {
|
||||
singleTime: [/\d{1,2}:\d{2}(?::\d{2})?(?:\s*(?:AM|PM|am|pm))?/],
|
||||
timeRange: [/\d{1,2}:\d{2}(?:\s*(?:AM|PM|am|pm))?\s*[-–—~]\s*\d{1,2}:\d{2}(?:\s*(?:AM|PM|am|pm))?/],
|
||||
rangeSeparators: ["-", "–", "—", "~"],
|
||||
},
|
||||
timeDefaults: {
|
||||
preferredFormat: "24h",
|
||||
defaultPeriod: "PM",
|
||||
|
|
@ -413,9 +428,19 @@ describe("Enhanced Time Parsing Edge Cases", () => {
|
|||
});
|
||||
|
||||
test("should handle disabled time parsing", () => {
|
||||
const disabledConfig = {
|
||||
const disabledConfig: EnhancedTimeParsingConfig = {
|
||||
...DEFAULT_TIME_PARSING_CONFIG,
|
||||
enabled: false,
|
||||
timePatterns: {
|
||||
singleTime: [/\d{1,2}:\d{2}(?::\d{2})?(?:\s*(?:AM|PM|am|pm))?/],
|
||||
timeRange: [/\d{1,2}:\d{2}(?:\s*(?:AM|PM|am|pm))?\s*[-–—~]\s*\d{1,2}:\d{2}(?:\s*(?:AM|PM|am|pm))?/],
|
||||
rangeSeparators: ["-", "–", "—", "~"],
|
||||
},
|
||||
timeDefaults: {
|
||||
preferredFormat: "24h",
|
||||
defaultPeriod: "PM",
|
||||
midnightCrossing: "next-day",
|
||||
},
|
||||
};
|
||||
|
||||
const disabledService = new TimeParsingService(disabledConfig);
|
||||
|
|
@ -437,6 +462,11 @@ describe("Enhanced Time Parsing Edge Cases", () => {
|
|||
timeRange: [/\d{1,2}h\d{2}-\d{1,2}h\d{2}/], // Custom range format
|
||||
rangeSeparators: ["-"],
|
||||
},
|
||||
timeDefaults: {
|
||||
preferredFormat: "24h",
|
||||
defaultPeriod: "PM",
|
||||
midnightCrossing: "next-day",
|
||||
},
|
||||
};
|
||||
|
||||
const customService = new TimeParsingService(customConfig);
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ describe("Enhanced Time Parsing Integration Tests", () => {
|
|||
completed: false,
|
||||
due: "2025-08-25",
|
||||
},
|
||||
getValue: jest.fn((prop) => {
|
||||
getValue: jest.fn((prop: any) => {
|
||||
if (prop.name === "title") return "Team meeting 14:00-16:00 tomorrow";
|
||||
if (prop.name === "status") return " ";
|
||||
if (prop.name === "completed") return false;
|
||||
|
|
@ -205,7 +205,7 @@ describe("Enhanced Time Parsing Integration Tests", () => {
|
|||
id: fileTask.id,
|
||||
title: fileTask.content,
|
||||
date: new Date(fileTask.metadata.dueDate!),
|
||||
task: fileTask,
|
||||
task: fileTask as any,
|
||||
timeInfo: {
|
||||
primaryTime: fileTask.metadata.enhancedDates!.startDateTime!,
|
||||
endTime: fileTask.metadata.enhancedDates!.endDateTime,
|
||||
|
|
@ -324,7 +324,7 @@ describe("Enhanced Time Parsing Integration Tests", () => {
|
|||
status: " ",
|
||||
completed: false,
|
||||
},
|
||||
getValue: jest.fn((prop) => {
|
||||
getValue: jest.fn((prop: any) => {
|
||||
if (prop.name === "title") return "Doctor appointment at 2:00 PM";
|
||||
if (prop.name === "status") return " ";
|
||||
if (prop.name === "completed") return false;
|
||||
|
|
@ -588,8 +588,8 @@ END:VCALENDAR`;
|
|||
|
||||
// Should have original ICS time information
|
||||
expect(task.icsEvent).toBeDefined();
|
||||
expect(task.icsEvent?.start).toBeDefined();
|
||||
expect(task.icsEvent?.end).toBeDefined();
|
||||
expect(task.icsEvent?.dtstart).toBeDefined();
|
||||
expect(task.icsEvent?.dtend).toBeDefined();
|
||||
|
||||
// Should have enhanced time components from ICS times
|
||||
expect(metadata.timeComponents).toBeDefined();
|
||||
|
|
|
|||
|
|
@ -271,7 +271,7 @@ describe("Enhanced Time Parsing Performance Tests", () => {
|
|||
status: " ",
|
||||
completed: false,
|
||||
},
|
||||
getValue: jest.fn((prop) => {
|
||||
getValue: jest.fn((prop: any) => {
|
||||
if (prop.name === "title") return `Task ${index} at ${9 + (index % 8)}:${(index % 4) * 15} AM`;
|
||||
if (prop.name === "status") return " ";
|
||||
if (prop.name === "completed") return false;
|
||||
|
|
@ -331,7 +331,13 @@ describe("Enhanced Time Parsing Performance Tests", () => {
|
|||
|
||||
batchSizes.forEach(batchSize => {
|
||||
const mockEntries = Array.from({ length: batchSize }, (_, i) => ({
|
||||
ctx: {},
|
||||
ctx: {
|
||||
_local: {},
|
||||
app: {} as any,
|
||||
filter: {},
|
||||
formulas: {},
|
||||
localUsed: false
|
||||
},
|
||||
file: {
|
||||
parent: null,
|
||||
deleted: false,
|
||||
|
|
@ -355,7 +361,7 @@ describe("Enhanced Time Parsing Performance Tests", () => {
|
|||
status: " ",
|
||||
completed: false,
|
||||
},
|
||||
getValue: jest.fn((prop) => {
|
||||
getValue: jest.fn((prop: any) => {
|
||||
if (prop.name === "title") return `Batch task ${i} at ${10 + (i % 6)}:${(i % 4) * 15}`;
|
||||
if (prop.name === "status") return " ";
|
||||
if (prop.name === "completed") return false;
|
||||
|
|
@ -714,7 +720,7 @@ describe("Enhanced Time Parsing Performance Tests", () => {
|
|||
// Benchmark parsing tasks without time
|
||||
const startTime = performance.now();
|
||||
tasksWithoutTime.forEach(taskText => {
|
||||
const result = enhancedTimeParsingService.parseTimeExpressions(taskText);
|
||||
const result = enhancedTimeParsingService.parseTimeExpressions(taskText) as EnhancedParsedTimeResult;
|
||||
// Access the result to ensure it's computed
|
||||
const hasTime = result.timeComponents && Object.keys(result.timeComponents).length > 0;
|
||||
});
|
||||
|
|
@ -744,7 +750,7 @@ describe("Enhanced Time Parsing Performance Tests", () => {
|
|||
for (let i = 0; i < iterations; i++) {
|
||||
edgeCases.forEach(edgeCase => {
|
||||
try {
|
||||
const result = enhancedTimeParsingService.parseTimeExpressions(edgeCase);
|
||||
const result = enhancedTimeParsingService.parseTimeExpressions(edgeCase) as EnhancedParsedTimeResult;
|
||||
// Access the result
|
||||
const hasTime = result.timeComponents && Object.keys(result.timeComponents).length > 0;
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ describe("FileTaskManager Time Integration", () => {
|
|||
status: " ",
|
||||
completed: false,
|
||||
},
|
||||
getValue: jest.fn((prop) => {
|
||||
getValue: jest.fn((prop: any) => {
|
||||
if (prop.name === "title") return "Meeting at 2:30 PM";
|
||||
if (prop.name === "status") return " ";
|
||||
if (prop.name === "completed") return false;
|
||||
|
|
@ -159,7 +159,7 @@ describe("FileTaskManager Time Integration", () => {
|
|||
status: " ",
|
||||
completed: false,
|
||||
},
|
||||
getValue: jest.fn((prop) => {
|
||||
getValue: jest.fn((prop: any) => {
|
||||
if (prop.name === "title") return "Workshop 9:00-17:00";
|
||||
if (prop.name === "status") return " ";
|
||||
if (prop.name === "completed") return false;
|
||||
|
|
@ -209,7 +209,7 @@ describe("FileTaskManager Time Integration", () => {
|
|||
completed: false,
|
||||
due: "2025-08-25", // Date in YYYY-MM-DD format
|
||||
},
|
||||
getValue: jest.fn((prop) => {
|
||||
getValue: jest.fn((prop: any) => {
|
||||
if (prop.name === "title") return "Doctor appointment at 3:30 PM";
|
||||
if (prop.name === "status") return " ";
|
||||
if (prop.name === "completed") return false;
|
||||
|
|
@ -269,7 +269,7 @@ describe("FileTaskManager Time Integration", () => {
|
|||
status: " ",
|
||||
completed: false,
|
||||
},
|
||||
getValue: jest.fn((prop) => {
|
||||
getValue: jest.fn((prop: any) => {
|
||||
if (prop.name === "title") return "Simple task without time";
|
||||
if (prop.name === "status") return " ";
|
||||
if (prop.name === "completed") return false;
|
||||
|
|
@ -315,7 +315,7 @@ describe("FileTaskManager Time Integration", () => {
|
|||
status: " ",
|
||||
completed: false,
|
||||
},
|
||||
getValue: jest.fn((prop) => {
|
||||
getValue: jest.fn((prop: any) => {
|
||||
if (prop.name === "title") return "Meeting at 2:00 PM";
|
||||
if (prop.name === "status") return " ";
|
||||
if (prop.name === "completed") return false;
|
||||
|
|
@ -375,7 +375,7 @@ describe("FileTaskManager Time Integration", () => {
|
|||
status: " ",
|
||||
completed: false,
|
||||
},
|
||||
getValue: jest.fn((prop) => {
|
||||
getValue: jest.fn((prop: any) => {
|
||||
if (prop.name === "title") return "Task with invalid time 25:99";
|
||||
if (prop.name === "status") return " ";
|
||||
if (prop.name === "completed") return false;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { MarkdownTaskParser, ConfigurableTaskParser } from "../dataflow/core/Con
|
|||
import { TimeParsingService } from "../services/time-parsing-service";
|
||||
import { TimeParsingConfig } from "../services/time-parsing-service";
|
||||
import { TaskParserConfig, MetadataParseMode } from "../types/TaskParserConfig";
|
||||
import { EnhancedStandardTaskMetadata } from "../types/time-parsing";
|
||||
|
||||
describe("Inline Task Time Integration", () => {
|
||||
let timeParsingService: TimeParsingService;
|
||||
|
|
@ -49,10 +50,10 @@ describe("Inline Task Time Integration", () => {
|
|||
const task = tasks[0];
|
||||
|
||||
expect(task.content).toBe("Meeting at 2:30 PM");
|
||||
expect(task.metadata.timeComponents).toBeDefined();
|
||||
expect((task.metadata as EnhancedStandardTaskMetadata).timeComponents).toBeDefined();
|
||||
|
||||
// Check time component (could be dueTime or scheduledTime based on context)
|
||||
const timeComponent = task.metadata.timeComponents?.dueTime || task.metadata.timeComponents?.scheduledTime;
|
||||
const timeComponent = (task.metadata as EnhancedStandardTaskMetadata).timeComponents?.dueTime || (task.metadata as EnhancedStandardTaskMetadata).timeComponents?.scheduledTime;
|
||||
expect(timeComponent).toBeDefined();
|
||||
expect(timeComponent?.hour).toBe(14);
|
||||
expect(timeComponent?.minute).toBe(30);
|
||||
|
|
@ -66,9 +67,9 @@ describe("Inline Task Time Integration", () => {
|
|||
const task = tasks[0];
|
||||
|
||||
expect(task.content).toBe("Call client at 15:45");
|
||||
expect(task.metadata.timeComponents).toBeDefined();
|
||||
expect((task.metadata as EnhancedStandardTaskMetadata).timeComponents).toBeDefined();
|
||||
|
||||
const timeComponent = task.metadata.timeComponents?.dueTime || task.metadata.timeComponents?.scheduledTime;
|
||||
const timeComponent = (task.metadata as EnhancedStandardTaskMetadata).timeComponents?.dueTime || (task.metadata as EnhancedStandardTaskMetadata).timeComponents?.scheduledTime;
|
||||
expect(timeComponent).toBeDefined();
|
||||
expect(timeComponent?.hour).toBe(15);
|
||||
expect(timeComponent?.minute).toBe(45);
|
||||
|
|
@ -84,13 +85,13 @@ describe("Inline Task Time Integration", () => {
|
|||
const task = tasks[0];
|
||||
|
||||
expect(task.content).toBe("Workshop 9:00-17:00");
|
||||
expect(task.metadata.timeComponents).toBeDefined();
|
||||
expect(task.metadata.timeComponents?.startTime).toBeDefined();
|
||||
expect(task.metadata.timeComponents?.endTime).toBeDefined();
|
||||
expect(task.metadata.timeComponents?.startTime?.hour).toBe(9);
|
||||
expect(task.metadata.timeComponents?.startTime?.minute).toBe(0);
|
||||
expect(task.metadata.timeComponents?.endTime?.hour).toBe(17);
|
||||
expect(task.metadata.timeComponents?.endTime?.minute).toBe(0);
|
||||
expect((task.metadata as EnhancedStandardTaskMetadata).timeComponents).toBeDefined();
|
||||
expect((task.metadata as EnhancedStandardTaskMetadata).timeComponents?.startTime).toBeDefined();
|
||||
expect((task.metadata as EnhancedStandardTaskMetadata).timeComponents?.endTime).toBeDefined();
|
||||
expect((task.metadata as EnhancedStandardTaskMetadata).timeComponents?.startTime?.hour).toBe(9);
|
||||
expect((task.metadata as EnhancedStandardTaskMetadata).timeComponents?.startTime?.minute).toBe(0);
|
||||
expect((task.metadata as EnhancedStandardTaskMetadata).timeComponents?.endTime?.hour).toBe(17);
|
||||
expect((task.metadata as EnhancedStandardTaskMetadata).timeComponents?.endTime?.minute).toBe(0);
|
||||
});
|
||||
|
||||
it("should extract 12-hour format time range", () => {
|
||||
|
|
@ -101,13 +102,13 @@ describe("Inline Task Time Integration", () => {
|
|||
const task = tasks[0];
|
||||
|
||||
expect(task.content).toBe("Meeting 2:30 PM - 4:00 PM");
|
||||
expect(task.metadata.timeComponents).toBeDefined();
|
||||
expect(task.metadata.timeComponents?.startTime).toBeDefined();
|
||||
expect(task.metadata.timeComponents?.endTime).toBeDefined();
|
||||
expect(task.metadata.timeComponents?.startTime?.hour).toBe(14);
|
||||
expect(task.metadata.timeComponents?.startTime?.minute).toBe(30);
|
||||
expect(task.metadata.timeComponents?.endTime?.hour).toBe(16);
|
||||
expect(task.metadata.timeComponents?.endTime?.minute).toBe(0);
|
||||
expect((task.metadata as EnhancedStandardTaskMetadata).timeComponents).toBeDefined();
|
||||
expect((task.metadata as EnhancedStandardTaskMetadata).timeComponents?.startTime).toBeDefined();
|
||||
expect((task.metadata as EnhancedStandardTaskMetadata).timeComponents?.endTime).toBeDefined();
|
||||
expect((task.metadata as EnhancedStandardTaskMetadata).timeComponents?.startTime?.hour).toBe(14);
|
||||
expect((task.metadata as EnhancedStandardTaskMetadata).timeComponents?.startTime?.minute).toBe(30);
|
||||
expect((task.metadata as EnhancedStandardTaskMetadata).timeComponents?.endTime?.hour).toBe(16);
|
||||
expect((task.metadata as EnhancedStandardTaskMetadata).timeComponents?.endTime?.minute).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -120,17 +121,17 @@ describe("Inline Task Time Integration", () => {
|
|||
const task = tasks[0];
|
||||
|
||||
expect(task.content).toBe("Doctor appointment at 3:30 PM");
|
||||
expect(task.metadata.timeComponents).toBeDefined();
|
||||
expect((task.metadata as EnhancedStandardTaskMetadata).timeComponents).toBeDefined();
|
||||
|
||||
// Check time component
|
||||
const timeComponent = task.metadata.timeComponents?.dueTime || task.metadata.timeComponents?.scheduledTime;
|
||||
const timeComponent = (task.metadata as EnhancedStandardTaskMetadata).timeComponents?.dueTime || (task.metadata as EnhancedStandardTaskMetadata).timeComponents?.scheduledTime;
|
||||
expect(timeComponent).toBeDefined();
|
||||
expect(timeComponent?.hour).toBe(15);
|
||||
expect(timeComponent?.minute).toBe(30);
|
||||
|
||||
// Check that enhanced datetime was created
|
||||
expect(task.metadata.enhancedDates?.dueDateTime).toBeDefined();
|
||||
const dueDateTime = task.metadata.enhancedDates?.dueDateTime;
|
||||
expect((task.metadata as EnhancedStandardTaskMetadata).enhancedDates?.dueDateTime).toBeDefined();
|
||||
const dueDateTime = (task.metadata as EnhancedStandardTaskMetadata).enhancedDates?.dueDateTime;
|
||||
if (dueDateTime) {
|
||||
expect(dueDateTime.getFullYear()).toBe(2025);
|
||||
expect(dueDateTime.getMonth()).toBe(7); // August (0-based)
|
||||
|
|
@ -148,15 +149,15 @@ describe("Inline Task Time Integration", () => {
|
|||
const task = tasks[0];
|
||||
|
||||
expect(task.content).toBe("Project deadline at 5:00 PM");
|
||||
expect(task.metadata.timeComponents).toBeDefined();
|
||||
expect((task.metadata as EnhancedStandardTaskMetadata).timeComponents).toBeDefined();
|
||||
|
||||
const timeComponent = task.metadata.timeComponents?.dueTime || task.metadata.timeComponents?.scheduledTime;
|
||||
const timeComponent = (task.metadata as EnhancedStandardTaskMetadata).timeComponents?.dueTime || (task.metadata as EnhancedStandardTaskMetadata).timeComponents?.scheduledTime;
|
||||
expect(timeComponent).toBeDefined();
|
||||
expect(timeComponent?.hour).toBe(17);
|
||||
expect(timeComponent?.minute).toBe(0);
|
||||
|
||||
// Check enhanced datetime
|
||||
expect(task.metadata.enhancedDates?.dueDateTime).toBeDefined();
|
||||
expect((task.metadata as EnhancedStandardTaskMetadata).enhancedDates?.dueDateTime).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -172,18 +173,18 @@ describe("Inline Task Time Integration", () => {
|
|||
|
||||
// First task
|
||||
expect(tasks[0].content).toBe("Morning meeting at 9:00 AM");
|
||||
const time1 = tasks[0].metadata.timeComponents?.dueTime || tasks[0].metadata.timeComponents?.scheduledTime;
|
||||
const time1 = (tasks[0].metadata as EnhancedStandardTaskMetadata).timeComponents?.dueTime || (tasks[0].metadata as EnhancedStandardTaskMetadata).timeComponents?.scheduledTime;
|
||||
expect(time1?.hour).toBe(9);
|
||||
expect(time1?.minute).toBe(0);
|
||||
|
||||
// Second task (time range)
|
||||
expect(tasks[1].content).toBe("Lunch break 12:00-13:00");
|
||||
expect(tasks[1].metadata.timeComponents?.startTime?.hour).toBe(12);
|
||||
expect(tasks[1].metadata.timeComponents?.endTime?.hour).toBe(13);
|
||||
expect((tasks[1].metadata as EnhancedStandardTaskMetadata).timeComponents?.startTime?.hour).toBe(12);
|
||||
expect((tasks[1].metadata as EnhancedStandardTaskMetadata).timeComponents?.endTime?.hour).toBe(13);
|
||||
|
||||
// Third task
|
||||
expect(tasks[2].content).toBe("Afternoon call at 3:30 PM");
|
||||
const time3 = tasks[2].metadata.timeComponents?.dueTime || tasks[2].metadata.timeComponents?.scheduledTime;
|
||||
const time3 = (tasks[2].metadata as EnhancedStandardTaskMetadata).timeComponents?.dueTime || (tasks[2].metadata as EnhancedStandardTaskMetadata).timeComponents?.scheduledTime;
|
||||
expect(time3?.hour).toBe(15);
|
||||
expect(time3?.minute).toBe(30);
|
||||
});
|
||||
|
|
@ -201,17 +202,17 @@ describe("Inline Task Time Integration", () => {
|
|||
|
||||
// Parent task (time range)
|
||||
expect(tasks[0].content).toBe("Project meeting 2:00 PM - 4:00 PM");
|
||||
expect(tasks[0].metadata.timeComponents?.startTime?.hour).toBe(14);
|
||||
expect(tasks[0].metadata.timeComponents?.endTime?.hour).toBe(16);
|
||||
expect((tasks[0].metadata as EnhancedStandardTaskMetadata).timeComponents?.startTime?.hour).toBe(14);
|
||||
expect((tasks[0].metadata as EnhancedStandardTaskMetadata).timeComponents?.endTime?.hour).toBe(16);
|
||||
|
||||
// Child tasks
|
||||
expect(tasks[1].content).toBe("Review agenda at 1:45 PM");
|
||||
const time1 = tasks[1].metadata.timeComponents?.dueTime || tasks[1].metadata.timeComponents?.scheduledTime;
|
||||
const time1 = (tasks[1].metadata as EnhancedStandardTaskMetadata).timeComponents?.dueTime || (tasks[1].metadata as EnhancedStandardTaskMetadata).timeComponents?.scheduledTime;
|
||||
expect(time1?.hour).toBe(13);
|
||||
expect(time1?.minute).toBe(45);
|
||||
|
||||
expect(tasks[2].content).toBe("Prepare slides at 1:30 PM");
|
||||
const time2 = tasks[2].metadata.timeComponents?.dueTime || tasks[2].metadata.timeComponents?.scheduledTime;
|
||||
const time2 = (tasks[2].metadata as EnhancedStandardTaskMetadata).timeComponents?.dueTime || (tasks[2].metadata as EnhancedStandardTaskMetadata).timeComponents?.scheduledTime;
|
||||
expect(time2?.hour).toBe(13);
|
||||
expect(time2?.minute).toBe(30);
|
||||
});
|
||||
|
|
@ -226,8 +227,8 @@ describe("Inline Task Time Integration", () => {
|
|||
const task = tasks[0];
|
||||
|
||||
expect(task.content).toBe("Simple task without time");
|
||||
expect(task.metadata.timeComponents).toBeUndefined();
|
||||
expect(task.metadata.enhancedDates).toBeUndefined();
|
||||
expect((task.metadata as EnhancedStandardTaskMetadata).timeComponents).toBeUndefined();
|
||||
expect((task.metadata as EnhancedStandardTaskMetadata).enhancedDates).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should handle invalid time formats gracefully", () => {
|
||||
|
|
@ -250,7 +251,7 @@ describe("Inline Task Time Integration", () => {
|
|||
const task = tasks[0];
|
||||
|
||||
expect(task.content).toBe("Meeting at 2:30 PM");
|
||||
expect(task.metadata.timeComponents).toBeUndefined();
|
||||
expect((task.metadata as EnhancedStandardTaskMetadata).timeComponents).toBeUndefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -57,7 +57,7 @@ describe("TimeParsingSettingsIntegration", () => {
|
|||
service.updateConfig(updatedConfig);
|
||||
|
||||
// Verify the configuration was updated
|
||||
const config = service.getConfig();
|
||||
const config = service.getConfig() as EnhancedTimeParsingConfig;
|
||||
expect(config.timeDefaults?.preferredFormat).toBe("12h");
|
||||
});
|
||||
|
||||
|
|
@ -74,7 +74,7 @@ describe("TimeParsingSettingsIntegration", () => {
|
|||
service.updateConfig(updatedConfig);
|
||||
|
||||
// Verify the configuration was updated
|
||||
const config = service.getConfig();
|
||||
const config = service.getConfig() as EnhancedTimeParsingConfig;
|
||||
expect(config.timeDefaults?.defaultPeriod).toBe("PM");
|
||||
});
|
||||
|
||||
|
|
@ -91,7 +91,7 @@ describe("TimeParsingSettingsIntegration", () => {
|
|||
service.updateConfig(updatedConfig);
|
||||
|
||||
// Verify the configuration was updated
|
||||
const config = service.getConfig();
|
||||
const config = service.getConfig() as EnhancedTimeParsingConfig;
|
||||
expect(config.timeDefaults?.midnightCrossing).toBe("same-day");
|
||||
});
|
||||
|
||||
|
|
@ -108,7 +108,7 @@ describe("TimeParsingSettingsIntegration", () => {
|
|||
service.updateConfig(updatedConfig);
|
||||
|
||||
// Verify the configuration was updated
|
||||
const config = service.getConfig();
|
||||
const config = service.getConfig() as EnhancedTimeParsingConfig;
|
||||
expect(config.timePatterns?.rangeSeparators).toEqual(["-", "to", "until"]);
|
||||
});
|
||||
|
||||
|
|
@ -126,7 +126,7 @@ describe("TimeParsingSettingsIntegration", () => {
|
|||
service.updateConfig(updatedConfig);
|
||||
|
||||
// Verify the configuration was updated
|
||||
const config = service.getConfig();
|
||||
const config = service.getConfig() as EnhancedTimeParsingConfig;
|
||||
expect(config.dateKeywords.start).toEqual(["begin", "commence", "initiate"]);
|
||||
expect(config.dateKeywords.due).toEqual(["deadline", "expires", "finish"]);
|
||||
expect(config.dateKeywords.scheduled).toEqual(["planned", "arranged", "set"]);
|
||||
|
|
@ -211,7 +211,7 @@ describe("TimeParsingSettingsIntegration", () => {
|
|||
enabled: false,
|
||||
});
|
||||
|
||||
const config = service.getConfig();
|
||||
const config = service.getConfig() as EnhancedTimeParsingConfig;
|
||||
expect(config.enabled).toBe(false);
|
||||
// Other settings should remain unchanged
|
||||
expect(config.supportedLanguages).toEqual(["en", "zh"]);
|
||||
|
|
@ -264,7 +264,7 @@ describe("TimeParsingSettingsIntegration", () => {
|
|||
service.updateConfig(config12h);
|
||||
|
||||
// Verify initial configuration
|
||||
let config = service.getConfig();
|
||||
let config = service.getConfig() as EnhancedTimeParsingConfig;
|
||||
expect(config.timeDefaults?.preferredFormat).toBe("12h");
|
||||
|
||||
// Switch to 24h format
|
||||
|
|
@ -279,7 +279,7 @@ describe("TimeParsingSettingsIntegration", () => {
|
|||
service.updateConfig(config24h);
|
||||
|
||||
// Verify configuration was updated
|
||||
config = service.getConfig();
|
||||
config = service.getConfig() as EnhancedTimeParsingConfig;
|
||||
expect(config.timeDefaults?.preferredFormat).toBe("24h");
|
||||
});
|
||||
|
||||
|
|
@ -296,7 +296,7 @@ describe("TimeParsingSettingsIntegration", () => {
|
|||
service.updateConfig(customConfig);
|
||||
|
||||
// Verify configuration was updated
|
||||
const config = service.getConfig();
|
||||
const config = service.getConfig() as EnhancedTimeParsingConfig;
|
||||
expect(config.timePatterns?.rangeSeparators).toEqual(["-", "~", "to", "until", "through"]);
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -599,6 +599,11 @@ export class DataflowOrchestrator {
|
|||
this.workerOrchestrator.setWorkerProcessingEnabled(enableWorkerProcessing);
|
||||
}
|
||||
|
||||
// Update TimeParsingService configuration
|
||||
if (settings.timeParsing && this.timeParsingService) {
|
||||
this.timeParsingService.updateConfig(settings.timeParsing);
|
||||
}
|
||||
|
||||
// Update FileSource if needed
|
||||
if (settings?.fileSource?.enabled && !this.fileSource) {
|
||||
// Initialize FileSource if enabled but not yet created
|
||||
|
|
@ -1086,18 +1091,6 @@ export class DataflowOrchestrator {
|
|||
this.projectResolver.updateOptions(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update settings for all components
|
||||
*/
|
||||
updateSettings(settings: any): void {
|
||||
// Update TimeParsingService configuration
|
||||
if (settings.timeParsing) {
|
||||
this.timeParsingService.updateConfig(settings.timeParsing);
|
||||
}
|
||||
|
||||
// Update other components as needed
|
||||
// This method can be extended to update other services when their settings change
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the query API for external access
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ export class DateInheritanceAugmentor {
|
|||
(timeComponents.dueTime && !metadata.dueDate) ||
|
||||
(timeComponents.scheduledTime && !metadata.scheduledDate);
|
||||
|
||||
return hasTimeWithoutDate;
|
||||
return hasTimeWithoutDate || false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -370,15 +370,12 @@ export class DateInheritanceAugmentor {
|
|||
switch (type) {
|
||||
case 'startDate':
|
||||
updatedMetadata.startDate = timestamp;
|
||||
updatedTask.startDate = timestamp; // Legacy field
|
||||
break;
|
||||
case 'dueDate':
|
||||
updatedMetadata.dueDate = timestamp;
|
||||
updatedTask.dueDate = timestamp; // Legacy field
|
||||
break;
|
||||
case 'scheduledDate':
|
||||
updatedMetadata.scheduledDate = timestamp;
|
||||
updatedTask.scheduledDate = timestamp; // Legacy field
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -361,7 +361,10 @@ export class IcsManager extends Component {
|
|||
);
|
||||
|
||||
// Extract time components from event description and preserve original ICS time information
|
||||
const enhancedMetadata = this.extractTimeComponentsFromIcsEvent(event, processedEvent);
|
||||
const enhancedMetadata = this.extractTimeComponentsFromIcsEvent(event, {
|
||||
...event,
|
||||
...processedEvent,
|
||||
});
|
||||
|
||||
const task: IcsTask = {
|
||||
id: `ics-${event.source.id}-${event.uid}`,
|
||||
|
|
@ -437,7 +440,10 @@ export class IcsManager extends Component {
|
|||
);
|
||||
|
||||
// Extract time components from event description and preserve original ICS time information
|
||||
const enhancedMetadata = this.extractTimeComponentsFromIcsEvent(event, processedEvent);
|
||||
const enhancedMetadata = this.extractTimeComponentsFromIcsEvent(event, {
|
||||
...event,
|
||||
...processedEvent,
|
||||
});
|
||||
|
||||
const task: IcsTask = {
|
||||
id: `ics-${event.source.id}-${event.uid}`,
|
||||
|
|
|
|||
|
|
@ -264,7 +264,7 @@ export class DateInheritanceService {
|
|||
// Return default info for non-existent files
|
||||
return {
|
||||
ctime: new Date(),
|
||||
dailyNoteDate: null,
|
||||
dailyNoteDate: undefined,
|
||||
metadataDate: undefined,
|
||||
isDailyNote: false,
|
||||
cachedAt: new Date(),
|
||||
|
|
@ -277,11 +277,13 @@ export class DateInheritanceService {
|
|||
const mtime = fileStat?.mtime || 0;
|
||||
|
||||
// Extract daily note date from file path/title
|
||||
const dailyNoteDate = this.extractDailyNoteDate(filePath);
|
||||
const isDailyNote = dailyNoteDate !== null;
|
||||
const dailyNoteDateResult = this.extractDailyNoteDate(filePath);
|
||||
const dailyNoteDate = dailyNoteDateResult ?? undefined;
|
||||
const isDailyNote = dailyNoteDateResult !== null;
|
||||
|
||||
// Extract metadata date from frontmatter
|
||||
const metadataDate = await this.extractMetadataDate(file);
|
||||
const metadataDateResult = await this.extractMetadataDate(file);
|
||||
const metadataDate = metadataDateResult ?? undefined;
|
||||
|
||||
const fileDateInfo: FileDateInfo = {
|
||||
ctime,
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ export class TaskMigrationService {
|
|||
if (hasTimeComponents(migratedMeta)) {
|
||||
const timeComponents = migratedMeta.timeComponents!;
|
||||
for (const [key, component] of Object.entries(timeComponents)) {
|
||||
if (component && !validateTimeComponent(component)) {
|
||||
if (component && !validateTimeComponent(component as TimeComponent)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -209,22 +209,24 @@ div[data-type^="tg-timeline-sidebar-view"] .timeline-event-time.timeline-event-t
|
|||
font-weight: 600;
|
||||
min-width: 80px;
|
||||
position: relative;
|
||||
animation: subtle-pulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
div[data-type^="tg-timeline-sidebar-view"] .timeline-event-time.timeline-event-time-range::after {
|
||||
content: "⏱";
|
||||
position: absolute;
|
||||
top: -2px;
|
||||
right: -2px;
|
||||
top: -3px;
|
||||
right: -3px;
|
||||
font-size: 10px;
|
||||
background-color: var(--background-primary);
|
||||
border-radius: 50%;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px solid var(--interactive-accent);
|
||||
border: 2px solid var(--interactive-accent);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
div[data-type^="tg-timeline-sidebar-view"] .timeline-event-time.timeline-event-time-default {
|
||||
|
|
@ -712,6 +714,15 @@ div[data-type^="tg-timeline-sidebar-view"]
|
|||
}
|
||||
}
|
||||
|
||||
@keyframes subtle-pulse {
|
||||
0%, 100% {
|
||||
box-shadow: 0 0 0 0 rgba(var(--interactive-accent-rgb), 0.4);
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 0 0 4px rgba(var(--interactive-accent-rgb), 0.1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Focus Mode */
|
||||
div[data-type^="tg-timeline-sidebar-view"] .timeline-content.focus-mode {
|
||||
position: relative;
|
||||
|
|
|
|||
30
src/types/task.d.ts
vendored
30
src/types/task.d.ts
vendored
|
|
@ -3,7 +3,6 @@
|
|||
*/
|
||||
|
||||
import { Component, EventRef, TFile } from "obsidian";
|
||||
import { TimeComponent } from "./time-parsing";
|
||||
|
||||
/** Base task interface with only core required fields */
|
||||
export interface BaseTask {
|
||||
|
|
@ -79,32 +78,6 @@ export interface StandardTaskMetadata {
|
|||
[key: string]: any;
|
||||
}
|
||||
|
||||
/** Enhanced task metadata interface with time components */
|
||||
export interface EnhancedStandardTaskMetadata extends StandardTaskMetadata {
|
||||
/** Time-specific metadata (separate from date timestamps) */
|
||||
timeComponents?: {
|
||||
/** Start time component */
|
||||
startTime?: TimeComponent;
|
||||
/** End time component (for time ranges) */
|
||||
endTime?: TimeComponent;
|
||||
/** Due time component */
|
||||
dueTime?: TimeComponent;
|
||||
/** Scheduled time component */
|
||||
scheduledTime?: TimeComponent;
|
||||
};
|
||||
|
||||
/** Enhanced date fields that combine date + time */
|
||||
enhancedDates?: {
|
||||
/** Full datetime for start (combines startDate + startTime) */
|
||||
startDateTime?: Date;
|
||||
/** Full datetime for end (combines date + endTime) */
|
||||
endDateTime?: Date;
|
||||
/** Full datetime for due (combines dueDate + dueTime) */
|
||||
dueDateTime?: Date;
|
||||
/** Full datetime for scheduled (combines scheduledDate + scheduledTime) */
|
||||
scheduledDateTime?: Date;
|
||||
};
|
||||
}
|
||||
|
||||
export interface StandardFileTaskMetadata extends StandardTaskMetadata {
|
||||
/** Task source */
|
||||
|
|
@ -159,6 +132,9 @@ export interface Task<
|
|||
metadata: TMetadata;
|
||||
}
|
||||
|
||||
// Re-export EnhancedStandardTaskMetadata from time-parsing module
|
||||
export { EnhancedStandardTaskMetadata } from "./time-parsing";
|
||||
|
||||
/** Task with enhanced time component support */
|
||||
export type EnhancedTask = Task<EnhancedStandardTaskMetadata>;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { ParsedTimeResult, TimeParsingConfig } from "../services/time-parsing-service";
|
||||
import { StandardTaskMetadata } from "./task";
|
||||
|
||||
/**
|
||||
* Time component structure representing parsed time information
|
||||
|
|
@ -92,4 +93,33 @@ export interface EnhancedParseResult {
|
|||
result?: EnhancedParsedTimeResult;
|
||||
errors: TimeParsingError[];
|
||||
warnings: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Enhanced task metadata interface with time components
|
||||
*/
|
||||
export interface EnhancedStandardTaskMetadata extends StandardTaskMetadata {
|
||||
/** Time-specific metadata (separate from date timestamps) */
|
||||
timeComponents?: {
|
||||
/** Start time component */
|
||||
startTime?: TimeComponent;
|
||||
/** End time component (for time ranges) */
|
||||
endTime?: TimeComponent;
|
||||
/** Due time component */
|
||||
dueTime?: TimeComponent;
|
||||
/** Scheduled time component */
|
||||
scheduledTime?: TimeComponent;
|
||||
};
|
||||
|
||||
/** Enhanced date fields that combine date + time */
|
||||
enhancedDates?: {
|
||||
/** Full datetime for start (combines startDate + startTime) */
|
||||
startDateTime?: Date;
|
||||
/** Full datetime for end (combines date + endTime) */
|
||||
endDateTime?: Date;
|
||||
/** Full datetime for due (combines dueDate + dueTime) */
|
||||
dueDateTime?: Date;
|
||||
/** Full datetime for scheduled (combines scheduledDate + scheduledTime) */
|
||||
scheduledDateTime?: Date;
|
||||
};
|
||||
}
|
||||
22
styles.css
22
styles.css
File diff suppressed because one or more lines are too long
Loading…
Reference in a new issue