Skip to content

Commit

Permalink
Merge pull request #57 from terryli710/main
Browse files Browse the repository at this point in the history
update from main
  • Loading branch information
terryli710 authored Oct 24, 2023
2 parents 435d0a9 + e3e0d1b commit 8597bf6
Show file tree
Hide file tree
Showing 15 changed files with 530 additions and 56 deletions.
18 changes: 18 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,13 @@
"ts-jest": "^29.1.1"
},
"dependencies": {
"humanize-duration": "^3.30.0",
"humanized-duration": "^0.0.1",
"lucide-svelte": "^0.268.0",
"marked": "^6.0.0",
"obsidian": "latest",
"obsidian-dataview": "^0.5.56",
"parse-duration": "^1.1.0",
"runtypes": "^6.7.0",
"sugar": "^2.0.6",
"svelte": "^4.1.1",
Expand Down
51 changes: 50 additions & 1 deletion src/autoSuggestions/Suggester.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ export class AttributeSuggester {
// );

this.inputtableAttributes = [
'priority',
'due',
'duration',
'priority',
'project',
]
});
Expand All @@ -56,6 +57,9 @@ export class AttributeSuggester {
suggestions = suggestions.concat(
this.getDueSuggestions(lineText, cursorPos)
);
suggestions = suggestions.concat(
this.getDurationSuggestions(lineText, cursorPos)
)
suggestions = suggestions.concat(
this.getProjectSuggestions(lineText, cursorPos)
);
Expand Down Expand Up @@ -180,6 +184,51 @@ export class AttributeSuggester {
return suggestions;
}

getDurationSuggestions(
lineText: string,
cursorPos: number
): SuggestInformation[] {
let suggestions: SuggestInformation[] = [];

// Modify regex to capture the due date query
const durationRegexText = `${escapeRegExp(this.startingNotation)}\\s?duration:(.*?)${escapeRegExp(this.endingNotation)}`;
const durationRegex = new RegExp(durationRegexText, 'g');
const durationMatch = matchByPositionAndGroup(lineText, durationRegex, cursorPos, 1);
if (!durationMatch) return suggestions; // No match

// Get the due date query from the captured group
const durationQuery = (durationMatch[1] || '').trim();

const durationStringSelections = [
'5 minutes',
'10 minutes',
'15 minutes',
'30 minutes',
'1 hour',
'2 hours',
'3 hours',
];

// Use the dueQuery to filter the suggestions
const filteredDurationStrings = durationStringSelections.filter((durationString) =>
durationString.toLowerCase().startsWith(durationQuery.toLowerCase())
);

suggestions = filteredDurationStrings.map((durationString) => {
const replaceText = `${this.startingNotation}duration: ${durationString}${this.endingNotation} `;
return {
displayText: durationString,
replaceText: replaceText,
replaceFrom: durationMatch.index,
replaceTo: durationMatch.index + durationMatch[0].length,
cursorPosition: durationMatch.index + replaceText.length
};
});

return suggestions;

}

getProjectSuggestions(
lineText: string,
cursorPos: number
Expand Down
18 changes: 18 additions & 0 deletions src/components/icons/CalendarClock.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@


<script>
import LucideIcon from './LucideIcon.svelte';
export let width = "24";
export let height = "24";
export let ariaLabel = "chevrons-up-down";
const svgPath = `
<path d="M21 7.5V6a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h3.5"/>
<path d="M16 2v4"/>
<path d="M8 2v4"/>
<path d="M3 10h5"/>
<path d="M17.5 17.5 16 16.25V14"/>
<path d="M22 16a6 6 0 1 1-12 0 6 6 0 0 1 12 0Z"/>
`;
</script>
<LucideIcon width={width} height={height} svgPath={svgPath} ariaLabel={ariaLabel} class="task-card-icon" />

14 changes: 14 additions & 0 deletions src/components/icons/History.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@


<script>
import LucideIcon from './LucideIcon.svelte';
export let width = "24";
export let height = "24";
export let ariaLabel = "chevrons-up-down";
const svgPath = `
<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/>
<path d="M3 3v5h5"/><path d="M12 7v5l4 2"/>
`;
</script>
<LucideIcon width={width} height={height} svgPath={svgPath} ariaLabel={ariaLabel} class="task-card-icon" />

3 changes: 2 additions & 1 deletion src/renderer/TaskCardRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@
taskCardStatus: {
descriptionStatus: 'done',
projectStatus: 'done',
dueStatus: 'done'
dueStatus: 'done',
durationStatus: 'done'
},
markdownTask: null,
taskItemEl: taskItemEl,
Expand Down
14 changes: 14 additions & 0 deletions src/taskModule/task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ export type DueDate = {
timezone?: string | null;
};

export type Duration = {
hours: number;
minutes: number;
}

export type SectionID = string;
export type Priority = 1 | 2 | 3 | 4;
export type Order = number;
Expand All @@ -38,6 +43,7 @@ export interface TaskProperties {
children: TaskProperties[] | ObsidianTask[];

due?: DueDate | null;
duration?: Duration | null;
metadata?: {
taskDisplayParams?: TaskDisplayParams | null;
[key: string]: any;
Expand All @@ -59,6 +65,7 @@ export class ObsidianTask implements TaskProperties {
public children: TaskProperties[] | ObsidianTask[];

public due?: DueDate | null;
public duration?: Duration | null;

public metadata?: {
taskDisplayParams?: TaskDisplayParams | null;
Expand All @@ -78,6 +85,7 @@ export class ObsidianTask implements TaskProperties {
this.parent = props?.parent || null;
this.children = props?.children || [];
this.due = props?.due || null;
this.duration = props?.duration || null;
this.metadata = props?.metadata || {};
}

Expand Down Expand Up @@ -111,6 +119,12 @@ export class ObsidianTask implements TaskProperties {
return !!this.due.string;
}

hasDuration(): boolean {
if (!this.duration) return false;
// return if the duration string is not empty = hours and minutes all zero
return this.duration.hours > 0 || this.duration.minutes > 0;
}

setTaskDisplayParams(key: string, value: any): void {
this.metadata.taskDisplayParams = {
...this.metadata.taskDisplayParams,
Expand Down
21 changes: 20 additions & 1 deletion src/taskModule/taskParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import { logger } from '../utils/log';
import { escapeRegExp, extractTags } from '../utils/regexUtils';
import { kebabToCamel } from '../utils/stringCaseConverter';
import { toArray, toBoolean } from '../utils/typeConversion';
import { DueDate, ObsidianTask, Order, Priority, TaskProperties, TextPosition } from './task';
import { DueDate, Duration, ObsidianTask, Order, Priority, TaskProperties, TextPosition } from './task';
import { Project, ProjectModule } from './project';
import Sugar from 'sugar';
import { SettingStore } from '../settings';
import { DescriptionParser } from './description';
import parse from 'parse-duration';


export class TaskParser {
Expand Down Expand Up @@ -87,6 +88,7 @@ export class TaskParser {
task.parent = attributes.parent || null;
task.children = attributes.children || [];
task.due = attributes.due || null;
task.duration = attributes.duration || null;
task.metadata = attributes.metadata || {};

// Get labels from content
Expand Down Expand Up @@ -241,6 +243,9 @@ export class TaskParser {
case 'due':
task.due = tryParseAttribute('due', this.parseDue.bind(this), attributeValue, 'other');
break;
case 'duration':
task.duration = tryParseAttribute('duration', this.parseDuration.bind(this), attributeValue, 'other');
break;
case 'project':
task.project = tryParseAttribute('project', this.parseProject.bind(this), attributeValue, 'string');
break;
Expand Down Expand Up @@ -328,6 +333,7 @@ export class TaskParser {
task.order = parseJSONAttribute(metadata['order'], 'order', 0);
task.project = parseJSONAttribute(metadata['project'], 'project', null);
task.due = parseJSONAttribute(metadata['due'], 'due', null);
task.duration = parseJSONAttribute(metadata['duration'], 'duration', null);
task.metadata = parseJSONAttribute(metadata['metadata'], 'metadata', {});

// Optional attributes
Expand Down Expand Up @@ -422,6 +428,19 @@ export class TaskParser {
}
}

parseDuration(durationString: string): Duration | null {
const durationInMinutes = parse(durationString, 'm');
// Convert the difference to hours and minutes
const hours = Math.floor(durationInMinutes / 60);
const minutes = durationInMinutes % 60;

return {
hours: hours,
minutes: minutes
} as Duration;
}


parseProject(projectString: string): Project | null {
const project = this.projectModule.getProjectByName(projectString);
if (!project) {
Expand Down
7 changes: 5 additions & 2 deletions src/taskModule/taskSyncManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ type TaskCardStatus = {
descriptionStatus: 'editing' | 'done';
projectStatus: 'selecting' | 'done';
dueStatus: 'editing' | 'done';
durationStatus: 'editing' | 'done';
};

export interface ObsidianTaskSyncProps {
Expand Down Expand Up @@ -44,7 +45,8 @@ export class ObsidianTaskSyncManager implements ObsidianTaskSyncProps {
this.taskCardStatus = props?.taskCardStatus || {
descriptionStatus: 'done',
projectStatus: 'done',
dueStatus: 'done'
dueStatus: 'done',
durationStatus: 'done',
};
this.taskItemEl = props?.taskItemEl || null;
this.taskMetadata = props?.taskMetadata || {
Expand Down Expand Up @@ -118,7 +120,8 @@ export class ObsidianTaskSyncManager implements ObsidianTaskSyncProps {
const allowedStatuses = {
descriptionStatus: ['editing', 'done'],
projectStatus: ['selecting', 'done'],
dueStatus: ['editing', 'done']
dueStatus: ['editing', 'done'],
durationStatus: ['editing', 'done']
};
return allowedStatuses[key].includes(status);
}
Expand Down
Loading

0 comments on commit 8597bf6

Please sign in to comment.