diff --git a/src/calendars/FullNoteCalendar.test.ts b/src/calendars/FullNoteCalendar.test.ts index 85cbef4..242b3c4 100644 --- a/src/calendars/FullNoteCalendar.test.ts +++ b/src/calendars/FullNoteCalendar.test.ts @@ -46,6 +46,8 @@ const makeApp = (app: MockApp): ObsidianInterface => ({ const dirName = "events"; const color = "#BADA55"; +const timeNotInNoteTitle = false; +const timeInNoteTitle = true; describe("Note Calendar Tests", () => { it.each([ @@ -120,13 +122,19 @@ describe("Note Calendar Tests", () => { new MockAppBuilder(dirName) ) ) - .done() - ); - const calendar = new FullNoteCalendar(obsidian, color, dirName); - const res = await calendar.getEvents(); - expect(res.length).toBe(inputs.length); - const events = res.map((e) => e[0]); - const paths = res.map((e) => e[1].file.path); + ) + .done() + ); + const calendar = new FullNoteCalendar( + obsidian, + color, + dirName, + timeNotInNoteTitle + ); + const res = await calendar.getEvents(); + expect(res.length).toBe(inputs.length); + const events = res.map((e) => e[0]); + const paths = res.map((e) => e[1].file.path); expect( res.every((elt) => elt[1].lineNumber === undefined) @@ -162,8 +170,13 @@ describe("Note Calendar Tests", () => { it("creates an event", async () => { const obsidian = makeApp(MockAppBuilder.make().done()); - const calendar = new FullNoteCalendar(obsidian, color, dirName); - const event = { + const calendar = new FullNoteCalendar( + obsidian, + color, + dirName, + timeNotInNoteTitle + ); + const event: OFCEvent = { title: "Test Event", date: "2022-01-01", endDate: null, @@ -196,6 +209,42 @@ describe("Note Calendar Tests", () => { `); }); + it("creates an event with time in note title", async () => { + const obsidian = makeApp(MockAppBuilder.make().done()); + const calendar = new FullNoteCalendar( + obsidian, + color, + dirName, + timeInNoteTitle + ); + const event: OFCEvent = { + title: "Test Event", + date: "2022-01-01", + startTime: "11:00", + endTime: "12:30", + }; + + (obsidian.create as jest.Mock).mockReturnValue({ + path: join(dirName, "2022-01-01 1100 Test Event.md"), + }); + const { lineNumber } = await calendar.createEvent(event); + expect(lineNumber).toBeUndefined(); + expect(obsidian.create).toHaveBeenCalledTimes(1); + const returns = (obsidian.create as jest.Mock).mock.calls[0]; + expect(returns).toMatchInlineSnapshot(` + [ + "events/2022-01-01 1100 Test Event.md", + "--- + title: Test Event + date: 2022-01-01 + startTime: 11:00 + endTime: 12:30 + --- + ", + ] + `); + }); + it("cannot overwrite event", async () => { const event = { title: "Test Event", @@ -213,7 +262,12 @@ describe("Note Calendar Tests", () => { ) .done() ); - const calendar = new FullNoteCalendar(obsidian, color, dirName); + const calendar = new FullNoteCalendar( + obsidian, + color, + dirName, + timeNotInNoteTitle + ); await assertFailed( () => calendar.createEvent(parseEvent(event)), /already exists/ @@ -240,7 +294,12 @@ describe("Note Calendar Tests", () => { ) .done() ); - const calendar = new FullNoteCalendar(obsidian, color, dirName); + const calendar = new FullNoteCalendar( + obsidian, + color, + dirName, + timeNotInNoteTitle + ); const firstFile = obsidian.getAbstractFileByPath( join("events", filename) diff --git a/src/calendars/FullNoteCalendar.ts b/src/calendars/FullNoteCalendar.ts index c41e014..ea55593 100644 --- a/src/calendars/FullNoteCalendar.ts +++ b/src/calendars/FullNoteCalendar.ts @@ -2,13 +2,26 @@ import { TFile, TFolder, parseYaml } from "obsidian"; import { rrulestr } from "rrule"; import { EventPathLocation } from "../core/EventStore"; import { ObsidianInterface } from "../ObsidianAdapter"; -import { OFCEvent, EventLocation, validateEvent } from "../types"; +import { + OFCEvent, + EventLocation, + validateEvent, + isRangeTimeData, +} from "../types"; import { EditableCalendar, EditableEventResponse } from "./EditableCalendar"; -const basenameFromEvent = (event: OFCEvent): string => { +const basenameFromEvent = ( + event: OFCEvent, + timeInNoteTitle: boolean +): string => { switch (event.type) { case undefined: case "single": + if (timeInNoteTitle && isRangeTimeData(event)) { + return `${event.date} ${event.startTime.replace(":", "")} ${ + event.title + }`; + } return `${event.date} ${event.title}`; case "recurring": return `(Every ${event.daysOfWeek.join(",")}) ${event.title}`; @@ -17,7 +30,8 @@ const basenameFromEvent = (event: OFCEvent): string => { } }; -const filenameForEvent = (event: OFCEvent) => `${basenameFromEvent(event)}.md`; +const filenameForEvent = (event: OFCEvent, timeInNoteTitle: boolean) => + `${basenameFromEvent(event, timeInNoteTitle)}.md`; const FRONTMATTER_SEPARATOR = "---"; @@ -146,15 +160,25 @@ function modifyFrontmatterString( export default class FullNoteCalendar extends EditableCalendar { app: ObsidianInterface; private _directory: string; + private _timeInNoteTitle: boolean; - constructor(app: ObsidianInterface, color: string, directory: string) { + constructor( + app: ObsidianInterface, + color: string, + directory: string, + timeInNoteTitle: boolean + ) { super(color); this.app = app; this._directory = directory; + this._timeInNoteTitle = timeInNoteTitle; } get directory(): string { return this._directory; } + get timeInNoteTitle(): boolean { + return this._timeInNoteTitle; + } get type(): "local" { return "local"; @@ -216,7 +240,10 @@ export default class FullNoteCalendar extends EditableCalendar { } async createEvent(event: OFCEvent): Promise { - const path = `${this.directory}/${filenameForEvent(event)}`; + const path = `${this.directory}/${filenameForEvent( + event, + this.timeInNoteTitle + )}`; if (this.app.getAbstractFileByPath(path)) { throw new Error(`Event at ${path} already exists.`); } @@ -239,7 +266,10 @@ export default class FullNoteCalendar extends EditableCalendar { ); } - const updatedPath = `${file.parent.path}/${filenameForEvent(event)}`; + const updatedPath = `${file.parent.path}/${filenameForEvent( + event, + this.timeInNoteTitle + )}`; return { file: { path: updatedPath }, lineNumber: undefined }; } diff --git a/src/main.ts b/src/main.ts index db16e9c..0b0a26c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -28,7 +28,8 @@ export default class FullCalendarPlugin extends Plugin { ? new FullNoteCalendar( new ObsidianIO(this.app), info.color, - info.directory + info.directory, + info.timeInNoteTitle ) : null, dailynote: (info) => diff --git a/src/types/index.ts b/src/types/index.ts index 0a122d4..0f178c3 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -26,4 +26,4 @@ export type Authentication = { password: string; }; -export type CalDAVSource = Extract; +export type CalDAVSource = Extract; \ No newline at end of file diff --git a/src/ui/components/AddCalendarSource.tsx b/src/ui/components/AddCalendarSource.tsx index 2a1b4c8..77b58f7 100644 --- a/src/ui/components/AddCalendarSource.tsx +++ b/src/ui/components/AddCalendarSource.tsx @@ -232,6 +232,7 @@ export const AddCalendarSource = ({ const isCalDAV = source.type === "caldav"; const [setting, setSettingState] = useState(source); + const [isTimeInNoteTitle, setIsTimeInNoteTitle] = useState(false); const [submitting, setSubmitingState] = useState(false); const [submitText, setSubmitText] = useState( isCalDAV ? "Import Calendars" : "Add Calendar" @@ -272,6 +273,28 @@ export const AddCalendarSource = ({ directories={directories} /> )} + {source.type === "local" && ( +
+
+
+ Time in note title +
+
+ Format note title as <YYYY-MM-DD> + <HHDD> <Event title>.md. +
+
+
+ + setIsTimeInNoteTitle(e.target.checked) + } + type="checkbox" + /> +
+
+ )} {source.type === "dailynote" && (