diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 8fb6d7d..2da9c1d 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,6 +8,11 @@ "name": "fabledassistant-frontend", "version": "0.1.0", "dependencies": { + "@fullcalendar/core": "^6.1.20", + "@fullcalendar/daygrid": "^6.1.20", + "@fullcalendar/interaction": "^6.1.20", + "@fullcalendar/timegrid": "^6.1.20", + "@fullcalendar/vue3": "^6.1.20", "@tiptap/core": "^3.0.0", "@tiptap/extension-link": "^3.0.0", "@tiptap/extension-list": "^3.0.0", @@ -564,6 +569,55 @@ "license": "MIT", "optional": true }, + "node_modules/@fullcalendar/core": { + "version": "6.1.20", + "resolved": "https://registry.npmjs.org/@fullcalendar/core/-/core-6.1.20.tgz", + "integrity": "sha512-1cukXLlePFiJ8YKXn/4tMKsy0etxYLCkXk8nUCFi11nRONF2Ba2CD5b21/ovtOO2tL6afTJfwmc1ed3HG7eB1g==", + "license": "MIT", + "dependencies": { + "preact": "~10.12.1" + } + }, + "node_modules/@fullcalendar/daygrid": { + "version": "6.1.20", + "resolved": "https://registry.npmjs.org/@fullcalendar/daygrid/-/daygrid-6.1.20.tgz", + "integrity": "sha512-AO9vqhkLP77EesmJzuU+IGXgxNulsA8mgQHynclJ8U70vSwAVnbcLG9qftiTAFSlZjiY/NvhE7sflve6cJelyQ==", + "license": "MIT", + "peerDependencies": { + "@fullcalendar/core": "~6.1.20" + } + }, + "node_modules/@fullcalendar/interaction": { + "version": "6.1.20", + "resolved": "https://registry.npmjs.org/@fullcalendar/interaction/-/interaction-6.1.20.tgz", + "integrity": "sha512-p6txmc5txL0bMiPaJxe2ip6o0T384TyoD2KGdsU6UjZ5yoBlaY+dg7kxfnYKpYMzEJLG58n+URrHr2PgNL2fyA==", + "license": "MIT", + "peerDependencies": { + "@fullcalendar/core": "~6.1.20" + } + }, + "node_modules/@fullcalendar/timegrid": { + "version": "6.1.20", + "resolved": "https://registry.npmjs.org/@fullcalendar/timegrid/-/timegrid-6.1.20.tgz", + "integrity": "sha512-4H+/MWbz3ntA50lrPif+7TsvMeX3R1GSYjiLULz0+zEJ7/Yfd9pupZmAwUs/PBpA6aAcFmeRr0laWfcz1a9V1A==", + "license": "MIT", + "dependencies": { + "@fullcalendar/daygrid": "~6.1.20" + }, + "peerDependencies": { + "@fullcalendar/core": "~6.1.20" + } + }, + "node_modules/@fullcalendar/vue3": { + "version": "6.1.20", + "resolved": "https://registry.npmjs.org/@fullcalendar/vue3/-/vue3-6.1.20.tgz", + "integrity": "sha512-8qg6pS27II9QBwFkkJC+7SfflMpWqOe7i3ii5ODq9KpLAjwQAd/zjfq8RvKR1Yryoh5UmMCmvRbMB7i4RGtqog==", + "license": "MIT", + "peerDependencies": { + "@fullcalendar/core": "~6.1.20", + "vue": "^3.0.11" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -2994,6 +3048,16 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/preact": { + "version": "10.12.1", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.12.1.tgz", + "integrity": "sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, "node_modules/prosemirror-changeset": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/prosemirror-changeset/-/prosemirror-changeset-2.4.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 6dd33ae..92b847a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -9,6 +9,11 @@ "preview": "vite preview" }, "dependencies": { + "@fullcalendar/core": "^6.1.20", + "@fullcalendar/daygrid": "^6.1.20", + "@fullcalendar/interaction": "^6.1.20", + "@fullcalendar/timegrid": "^6.1.20", + "@fullcalendar/vue3": "^6.1.20", "@tiptap/core": "^3.0.0", "@tiptap/extension-link": "^3.0.0", "@tiptap/extension-list": "^3.0.0", diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 00db060..3412abe 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -82,6 +82,7 @@ function onGlobalKeydown(e: KeyboardEvent) { case "p": router.push("/projects"); break; case "c": router.push("/chat"); break; case "g": router.push("/graph"); break; + case "l": router.push("/calendar"); break; } return; } @@ -202,6 +203,12 @@ onUnmounted(() => { c Chat +
+ g + + + l + Calendar +
Esc Unfocus field → go home diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index d53055e..09724a7 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -516,3 +516,69 @@ export async function apiStreamPost( } } } + +// --------------------------------------------------------------------------- +// Calendar events +// --------------------------------------------------------------------------- + +export interface EventEntry { + id: number; + uid: string; + title: string; + start_dt: string; + end_dt: string | null; + all_day: boolean; + description: string; + location: string; + color: string; + recurrence: string | null; + caldav_uid: string; + project_id: number | null; + user_id: number; + created_at: string | null; + updated_at: string | null; +} + +export interface EventCreatePayload { + title: string; + start_dt: string; + end_dt?: string; + all_day?: boolean; + description?: string; + location?: string; + color?: string; + recurrence?: string; + project_id?: number; +} + +export interface EventUpdatePayload { + title?: string; + start_dt?: string; + end_dt?: string; + all_day?: boolean; + description?: string; + location?: string; + color?: string; + recurrence?: string; + project_id?: number; +} + +export async function listEvents(from: string, to: string): Promise { + return apiGet(`/api/events?from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}`); +} + +export async function createEvent(payload: EventCreatePayload): Promise { + return apiPost('/api/events', payload); +} + +export async function getEvent(id: number): Promise { + return apiGet(`/api/events/${id}`); +} + +export async function updateEvent(id: number, payload: EventUpdatePayload): Promise { + return apiPatch(`/api/events/${id}`, payload); +} + +export async function deleteEvent(id: number): Promise { + return apiDelete(`/api/events/${id}`); +} diff --git a/frontend/src/components/AppHeader.vue b/frontend/src/components/AppHeader.vue index 01e649c..a706590 100644 --- a/frontend/src/components/AppHeader.vue +++ b/frontend/src/components/AppHeader.vue @@ -77,6 +77,7 @@ router.afterEach(() => { Tasks Chat Graph + Calendar Briefing Shared
@@ -126,6 +127,7 @@ router.afterEach(() => { Tasks Chat Graph + Calendar Briefing Shared
diff --git a/frontend/src/components/EventSlideOver.vue b/frontend/src/components/EventSlideOver.vue new file mode 100644 index 0000000..a04d918 --- /dev/null +++ b/frontend/src/components/EventSlideOver.vue @@ -0,0 +1,444 @@ + + +