All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 1m11s
Chat (AIChat floating widget): conversationId was never captured from the API response, so every message created a new conversation with no context. Now creates the conversation upfront before streaming (same pattern as ChatContainer) so the ID persists across messages. Note history: was stored globally in UserAISettings, so enabling history on one note enabled it for ALL notes. Now each Note has its own historyEnabled boolean field. The "Enable history" action only affects the specific note. A migration adds the column with default false. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
234 lines
6.8 KiB
TypeScript
234 lines
6.8 KiB
TypeScript
export interface CheckItem {
|
|
id: string;
|
|
text: string;
|
|
checked: boolean;
|
|
}
|
|
|
|
/**
|
|
* Notebook model for organizing notes
|
|
*/
|
|
export interface Notebook {
|
|
id: string;
|
|
name: string;
|
|
icon: string | null;
|
|
color: string | null;
|
|
order: number;
|
|
userId: string;
|
|
createdAt: Date;
|
|
updatedAt: Date;
|
|
// Relations
|
|
notes?: Note[];
|
|
labels?: Label[];
|
|
}
|
|
|
|
/**
|
|
* Label model - contextual to notebooks
|
|
*/
|
|
export interface Label {
|
|
id: string;
|
|
name: string;
|
|
color: LabelColorName;
|
|
notebookId: string | null; // NEW: Belongs to a notebook
|
|
userId?: string | null; // DEPRECATED: Kept for backward compatibility
|
|
createdAt: Date;
|
|
updatedAt: Date;
|
|
// Relations
|
|
notebook?: Notebook | null;
|
|
}
|
|
|
|
export interface LinkMetadata {
|
|
url: string;
|
|
title?: string;
|
|
description?: string;
|
|
imageUrl?: string;
|
|
siteName?: string;
|
|
}
|
|
|
|
export interface Note {
|
|
id: string;
|
|
title: string | null;
|
|
content: string;
|
|
color: string;
|
|
isPinned: boolean;
|
|
isArchived: boolean;
|
|
trashedAt?: Date | null;
|
|
type: 'text' | 'checklist';
|
|
checkItems: CheckItem[] | null;
|
|
labels: string[] | null; // DEPRECATED: Array of label names stored as JSON string
|
|
images: string[] | null;
|
|
links: LinkMetadata[] | null;
|
|
reminder: Date | null;
|
|
isReminderDone: boolean;
|
|
reminderRecurrence: string | null;
|
|
reminderLocation: string | null;
|
|
isMarkdown: boolean;
|
|
dismissedFromRecent?: boolean;
|
|
size: NoteSize;
|
|
order: number;
|
|
createdAt: Date;
|
|
updatedAt: Date;
|
|
contentUpdatedAt: Date;
|
|
sharedWith?: string[];
|
|
userId?: string | null;
|
|
// Notebook relation (optional - null = "General Notes" / Inbox)
|
|
notebookId?: string | null;
|
|
notebook?: Notebook | null;
|
|
autoGenerated?: boolean | null;
|
|
aiProvider?: string | null;
|
|
historyEnabled?: boolean;
|
|
// Search result metadata (optional)
|
|
matchType?: 'exact' | 'related' | null;
|
|
searchScore?: number | null;
|
|
}
|
|
|
|
export interface NoteHistoryEntry {
|
|
id: string;
|
|
noteId: string;
|
|
userId: string;
|
|
version: number;
|
|
reason: string | null;
|
|
title: string | null;
|
|
content: string;
|
|
color: string;
|
|
isPinned: boolean;
|
|
isArchived: boolean;
|
|
type: 'text' | 'checklist';
|
|
checkItems: CheckItem[] | null;
|
|
labels: string[] | null;
|
|
images: string[] | null;
|
|
links: LinkMetadata[] | null;
|
|
isMarkdown: boolean;
|
|
size: NoteSize;
|
|
notebookId: string | null;
|
|
createdAt: Date;
|
|
}
|
|
|
|
export type NoteSize = 'small' | 'medium' | 'large';
|
|
|
|
export interface LabelWithColor {
|
|
name: string;
|
|
color: LabelColorName;
|
|
}
|
|
|
|
export const LABEL_COLORS = {
|
|
gray: {
|
|
bg: 'bg-zinc-100 dark:bg-zinc-800',
|
|
text: 'text-zinc-700 dark:text-zinc-300',
|
|
border: 'border-zinc-200 dark:border-zinc-700',
|
|
icon: 'text-zinc-500 dark:text-zinc-400'
|
|
},
|
|
red: {
|
|
bg: 'bg-rose-100 dark:bg-rose-900/40',
|
|
text: 'text-rose-700 dark:text-rose-300',
|
|
border: 'border-rose-200 dark:border-rose-800',
|
|
icon: 'text-rose-500 dark:text-rose-400'
|
|
},
|
|
orange: {
|
|
bg: 'bg-orange-100 dark:bg-orange-900/40',
|
|
text: 'text-orange-700 dark:text-orange-300',
|
|
border: 'border-orange-200 dark:border-orange-800',
|
|
icon: 'text-orange-500 dark:text-orange-400'
|
|
},
|
|
yellow: {
|
|
bg: 'bg-amber-100 dark:bg-amber-900/40',
|
|
text: 'text-amber-700 dark:text-amber-300',
|
|
border: 'border-amber-200 dark:border-amber-800',
|
|
icon: 'text-amber-500 dark:text-amber-400'
|
|
},
|
|
green: {
|
|
bg: 'bg-emerald-100 dark:bg-emerald-900/40',
|
|
text: 'text-emerald-700 dark:text-emerald-300',
|
|
border: 'border-emerald-200 dark:border-emerald-800',
|
|
icon: 'text-emerald-500 dark:text-emerald-400'
|
|
},
|
|
teal: {
|
|
bg: 'bg-teal-100 dark:bg-teal-900/40',
|
|
text: 'text-teal-700 dark:text-teal-300',
|
|
border: 'border-teal-200 dark:border-teal-800',
|
|
icon: 'text-teal-500 dark:text-teal-400'
|
|
},
|
|
blue: {
|
|
bg: 'bg-sky-100 dark:bg-sky-900/40',
|
|
text: 'text-sky-700 dark:text-sky-300',
|
|
border: 'border-sky-200 dark:border-sky-800',
|
|
icon: 'text-sky-500 dark:text-sky-400'
|
|
},
|
|
purple: {
|
|
bg: 'bg-violet-100 dark:bg-violet-900/40',
|
|
text: 'text-violet-700 dark:text-violet-300',
|
|
border: 'border-violet-200 dark:border-violet-800',
|
|
icon: 'text-violet-500 dark:text-violet-400'
|
|
},
|
|
pink: {
|
|
bg: 'bg-fuchsia-100 dark:bg-fuchsia-900/40',
|
|
text: 'text-fuchsia-700 dark:text-fuchsia-300',
|
|
border: 'border-fuchsia-200 dark:border-fuchsia-800',
|
|
icon: 'text-fuchsia-500 dark:text-fuchsia-400'
|
|
},
|
|
} as const;
|
|
|
|
export type LabelColorName = keyof typeof LABEL_COLORS
|
|
|
|
export const NOTE_COLORS = {
|
|
default: {
|
|
bg: 'bg-white dark:bg-zinc-900',
|
|
hover: 'hover:bg-gray-50 dark:hover:bg-zinc-800',
|
|
card: 'bg-white dark:bg-zinc-900 border-gray-200 dark:border-zinc-700'
|
|
},
|
|
red: {
|
|
bg: 'bg-red-50 dark:bg-red-950/30',
|
|
hover: 'hover:bg-red-100 dark:hover:bg-red-950/50',
|
|
card: 'bg-red-50 dark:bg-red-950/30 border-red-100 dark:border-red-900/50'
|
|
},
|
|
orange: {
|
|
bg: 'bg-orange-50 dark:bg-orange-950/30',
|
|
hover: 'hover:bg-orange-100 dark:hover:bg-orange-950/50',
|
|
card: 'bg-orange-50 dark:bg-orange-950/30 border-orange-100 dark:border-orange-900/50'
|
|
},
|
|
yellow: {
|
|
bg: 'bg-yellow-50 dark:bg-yellow-950/30',
|
|
hover: 'hover:bg-yellow-100 dark:hover:bg-yellow-950/50',
|
|
card: 'bg-yellow-50 dark:bg-yellow-950/30 border-yellow-100 dark:border-yellow-900/50'
|
|
},
|
|
green: {
|
|
bg: 'bg-green-50 dark:bg-green-950/30',
|
|
hover: 'hover:bg-green-100 dark:hover:bg-green-950/50',
|
|
card: 'bg-green-50 dark:bg-green-950/30 border-green-100 dark:border-green-900/50'
|
|
},
|
|
teal: {
|
|
bg: 'bg-teal-50 dark:bg-teal-950/30',
|
|
hover: 'hover:bg-teal-100 dark:hover:bg-teal-950/50',
|
|
card: 'bg-teal-50 dark:bg-teal-950/30 border-teal-100 dark:border-teal-900/50'
|
|
},
|
|
blue: {
|
|
bg: 'bg-blue-50 dark:bg-blue-950/30',
|
|
hover: 'hover:bg-blue-100 dark:hover:bg-blue-950/50',
|
|
card: 'bg-blue-50 dark:bg-blue-950/30 border-blue-100 dark:border-blue-900/50'
|
|
},
|
|
purple: {
|
|
bg: 'bg-purple-50 dark:bg-purple-950/30',
|
|
hover: 'hover:bg-purple-100 dark:hover:bg-purple-950/50',
|
|
card: 'bg-purple-50 dark:bg-purple-950/30 border-purple-100 dark:border-purple-900/50'
|
|
},
|
|
pink: {
|
|
bg: 'bg-pink-50 dark:bg-pink-950/30',
|
|
hover: 'hover:bg-pink-100 dark:hover:bg-pink-950/50',
|
|
card: 'bg-pink-50 dark:bg-pink-950/30 border-pink-100 dark:border-pink-900/50'
|
|
},
|
|
gray: {
|
|
bg: 'bg-gray-100 dark:bg-gray-800/50',
|
|
hover: 'hover:bg-gray-200 dark:hover:bg-gray-700/50',
|
|
card: 'bg-gray-100 dark:bg-gray-800/50 border-gray-200 dark:border-gray-700'
|
|
},
|
|
} as const;
|
|
|
|
export type NoteColor = keyof typeof NOTE_COLORS;
|
|
|
|
/**
|
|
* Query types for adaptive search weighting
|
|
* - 'exact': User searched with quotes, looking for exact match (e.g., "Error 404")
|
|
* - 'conceptual': User is asking a question or looking for concepts (e.g., "how to cook")
|
|
* - 'mixed': No specific pattern detected, use default weights
|
|
*/
|
|
export type QueryType = 'exact' | 'conceptual' | 'mixed';
|