12f71fabdf
CI & Build / Python lint (push) Successful in 4s
CI & Build / integration (push) Successful in 28s
CI & Build / TypeScript typecheck (push) Successful in 33s
CI & Build / Python tests (push) Successful in 46s
CI & Build / Build & push image (push) Successful in 44s
Frontend half of the narrowing (milestone #194); matches backend b49efdc.
- delete CalendarView, EventSlideOver, WeatherCard (orphan)
- drop /calendar route + nav link + the g→l keyboard shortcut
- strip the calendar-events API client + event/metadata bits from note
types and the notes store
- KnowledgeView: remove People/Places/Lists tabs, entity cards, create
buttons and the upcoming-events widget; keep notes/tasks/plans/processes
+ the overdue-task badge
- NoteEditorView: remove person/place/list forms + list-builder + entity
metadata; keep note + process editors (type select = Note/Process)
- DashboardView: drop the "Upcoming · 7 days" events rail card
- SettingsView: remove the CalDAV integration card + save/test (its
endpoints were deleted backend-side)
- prune the now-dead entity/event CSS
RecurrenceEditor + task recurrence rules are kept (task machinery, not
calendar). Verified by a full dangler sweep.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BPtbSzA4JLMAKgFZ8VTg7Q
136 lines
3.6 KiB
TypeScript
136 lines
3.6 KiB
TypeScript
import { ref } from "vue";
|
|
import { defineStore } from "pinia";
|
|
import { apiGet, apiPost, apiPut, apiDelete } from "@/api/client";
|
|
import { useToastStore } from "@/stores/toast";
|
|
import type { Note } from "@/types/note";
|
|
|
|
// Single-note + mutation surface. The list/filter/sort/pagination surface that
|
|
// backed the removed /notes list view was dropped in the 2026-06-02 drift-audit
|
|
// cleanup (no consumers — KnowledgeView and the editors use single-entity and
|
|
// mutation methods only).
|
|
export const useNotesStore = defineStore("notes", () => {
|
|
const currentNote = ref<Note | null>(null);
|
|
const loading = ref(false);
|
|
|
|
async function fetchNote(id: number) {
|
|
loading.value = true;
|
|
try {
|
|
currentNote.value = await apiGet<Note>(`/api/notes/${id}`);
|
|
} catch (e) {
|
|
useToastStore().show("Failed to load note", "error");
|
|
throw e;
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
}
|
|
|
|
async function createNote(data: {
|
|
title: string;
|
|
body: string;
|
|
tags?: string[];
|
|
project_id?: number | null;
|
|
milestone_id?: number | null;
|
|
note_type?: string;
|
|
}): Promise<Note> {
|
|
try {
|
|
return await apiPost<Note>("/api/notes", data);
|
|
} catch (e) {
|
|
useToastStore().show("Failed to create note", "error");
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
async function updateNote(
|
|
id: number,
|
|
data: Partial<Pick<Note, "title" | "body" | "tags" | "project_id" | "milestone_id" | "note_type">>
|
|
): Promise<Note> {
|
|
try {
|
|
const note = await apiPut<Note>(`/api/notes/${id}`, data);
|
|
if (currentNote.value?.id === id) {
|
|
currentNote.value = note;
|
|
}
|
|
return note;
|
|
} catch (e) {
|
|
useToastStore().show("Failed to update note", "error");
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
async function deleteNote(id: number) {
|
|
try {
|
|
await apiDelete(`/api/notes/${id}`);
|
|
if (currentNote.value?.id === id) {
|
|
currentNote.value = null;
|
|
}
|
|
} catch (e) {
|
|
useToastStore().show("Failed to delete note", "error");
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
async function resolveTitle(title: string): Promise<Note> {
|
|
return await apiPost<Note>("/api/notes/resolve-title", { title });
|
|
}
|
|
|
|
async function convertToTask(noteId: number): Promise<Note> {
|
|
try {
|
|
const note = await apiPost<Note>(
|
|
`/api/notes/${noteId}/convert-to-task`,
|
|
{}
|
|
);
|
|
if (currentNote.value?.id === noteId) {
|
|
currentNote.value = note;
|
|
}
|
|
return note;
|
|
} catch (e) {
|
|
useToastStore().show("Failed to convert to task", "error");
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
async function convertToNote(noteId: number): Promise<Note> {
|
|
try {
|
|
const note = await apiPost<Note>(
|
|
`/api/notes/${noteId}/convert-to-note`,
|
|
{}
|
|
);
|
|
if (currentNote.value?.id === noteId) {
|
|
currentNote.value = note;
|
|
}
|
|
return note;
|
|
} catch (e) {
|
|
useToastStore().show("Failed to convert to note", "error");
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
async function fetchBacklinks(
|
|
noteId: number
|
|
): Promise<{ type: string; id: number; title: string }[]> {
|
|
const data = await apiGet<{
|
|
backlinks: { type: string; id: number; title: string }[];
|
|
}>(`/api/notes/${noteId}/backlinks`);
|
|
return data.backlinks;
|
|
}
|
|
|
|
async function fetchAllTags(q?: string): Promise<string[]> {
|
|
const params = q ? `?q=${encodeURIComponent(q)}` : "";
|
|
const data = await apiGet<{ tags: string[] }>(`/api/notes/tags${params}`);
|
|
return data.tags;
|
|
}
|
|
|
|
return {
|
|
currentNote,
|
|
loading,
|
|
fetchNote,
|
|
createNote,
|
|
updateNote,
|
|
deleteNote,
|
|
resolveTitle,
|
|
convertToTask,
|
|
convertToNote,
|
|
fetchBacklinks,
|
|
fetchAllTags,
|
|
};
|
|
});
|