fix: update masonry grid sizing logic and notebook list padding

This commit is contained in:
Sepehr Ramezani
2026-02-14 14:20:32 +01:00
parent a0ffc9043b
commit 8f9031f076
580 changed files with 9789 additions and 42619 deletions

View File

@@ -41,3 +41,7 @@ yarn-error.log*
next-env.d.ts
/lib/generated/prisma
# generated
/prisma/client-generated
/_backup

View File

@@ -202,15 +202,9 @@ export default function HomePage() {
}
// Load pinned notes separately (shown in favorites section)
const pinned = await getPinnedNotes()
const pinned = await getPinnedNotes(notebookFilter || undefined)
// Filter pinned notes by current filters as well
if (notebookFilter) {
setPinnedNotes(pinned.filter((note: any) => note.notebookId === notebookFilter))
} else {
// If no notebook selected, only show pinned notes without notebook
setPinnedNotes(pinned.filter((note: any) => !note.notebookId))
}
setPinnedNotes(pinned)
// Load recent notes only if enabled in settings
if (showRecentNotes) {

View File

@@ -458,7 +458,13 @@ export async function updateNote(id: string, data: {
// Explicitly handle size to ensure it propagates
if ('size' in data && data.size) updateData.size = data.size
updateData.updatedAt = new Date()
// Only update contentUpdatedAt for actual content changes, NOT for property changes
// (size, color, isPinned, isArchived are properties, not content)
const contentFields = ['title', 'content', 'checkItems', 'images', 'links']
const isContentChange = contentFields.some(field => field in data)
if (isContentChange) {
updateData.contentUpdatedAt = new Date()
}
const note = await prisma.note.update({
where: { id, userId: session.user.id },
@@ -471,16 +477,15 @@ export async function updateNote(id: string, data: {
await syncLabels(session.user.id, data.labels || [])
}
// IMPORTANT: Call revalidatePath to ensure UI updates
// BUT skip if only updating size (let optimistic UI handle it)
const isSizeOnlyUpdate = Object.keys(data).length === 1 && 'size' in data
// Only revalidate for STRUCTURAL changes that affect the page layout/lists
// Content edits (title, content, size, color) use optimistic UI — no refresh needed
const structuralFields = ['isPinned', 'isArchived', 'labels', 'notebookId']
const isStructuralChange = structuralFields.some(field => field in data)
if (!isSizeOnlyUpdate) {
// Revalidate main page, the note itself, and both old and new notebook paths
if (isStructuralChange) {
revalidatePath('/')
revalidatePath(`/note/${id}`)
// If notebook changed, revalidate both notebook paths
if (data.notebookId !== undefined && data.notebookId !== oldNotebookId) {
if (oldNotebookId) {
revalidatePath(`/notebook/${oldNotebookId}`)
@@ -776,7 +781,7 @@ export async function getAllNotes(includeArchived = false) {
}
// Get pinned notes only
export async function getPinnedNotes() {
export async function getPinnedNotes(notebookId?: string) {
const session = await auth();
if (!session?.user?.id) return [];
@@ -787,7 +792,8 @@ export async function getPinnedNotes() {
where: {
userId: userId,
isPinned: true,
isArchived: false
isArchived: false,
...(notebookId !== undefined ? { notebookId } : {})
},
orderBy: [
{ order: 'asc' },
@@ -817,10 +823,10 @@ export async function getRecentNotes(limit: number = 3) {
const notes = await prisma.note.findMany({
where: {
userId: userId,
updatedAt: { gte: sevenDaysAgo },
contentUpdatedAt: { gte: sevenDaysAgo },
isArchived: false
},
orderBy: { updatedAt: 'desc' },
orderBy: { contentUpdatedAt: 'desc' },
take: limit
})

View File

@@ -3,28 +3,52 @@
import { useState } from 'react'
import { Note } from '@/lib/types'
import { NoteCard } from './note-card'
import { ChevronDown, ChevronUp } from 'lucide-react'
import { ChevronDown, ChevronUp, Pin } from 'lucide-react'
import { useLanguage } from '@/lib/i18n'
interface FavoritesSectionProps {
pinnedNotes: Note[]
onEdit?: (note: Note, readOnly?: boolean) => void
isLoading?: boolean
}
export function FavoritesSection({ pinnedNotes, onEdit }: FavoritesSectionProps) {
export function FavoritesSection({ pinnedNotes, onEdit, isLoading }: FavoritesSectionProps) {
const [isCollapsed, setIsCollapsed] = useState(false)
const { t } = useLanguage()
if (isLoading) {
return (
<section data-testid="favorites-section" className="mb-8">
<div className="flex items-center gap-2 mb-4 px-2 py-2">
<Pin className="w-5 h-5 text-muted-foreground animate-pulse" />
<div className="h-6 w-32 bg-muted rounded animate-pulse" />
</div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{[1, 2, 3].map((i) => (
<div key={i} className="h-40 bg-muted rounded-2xl animate-pulse" />
))}
</div>
</section>
)
}
// Don't show section if no pinned notes
if (pinnedNotes.length === 0) {
return null
}
return (
<section data-testid="favorites-section" className="mb-8">
{/* Collapsible Header */}
<button
onClick={() => setIsCollapsed(!isCollapsed)}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault()
setIsCollapsed(!isCollapsed)
}
}}
className="w-full flex items-center justify-between gap-2 mb-4 px-2 py-2 hover:bg-accent rounded-lg transition-colors min-h-[44px]"
aria-expanded={!isCollapsed}
aria-label={t('favorites.toggleSection') || 'Toggle pinned notes section'}
>
<div className="flex items-center gap-2">
<span className="text-2xl">📌</span>

View File

@@ -52,12 +52,12 @@
.masonry-item[data-size="medium"],
.note-card[data-size="medium"] {
min-height: 200px;
min-height: 350px;
}
.masonry-item[data-size="large"],
.note-card[data-size="large"] {
min-height: 300px;
min-height: 500px;
}
/* Drag State Styles - Clean and flat behavior requested by user */
@@ -134,12 +134,12 @@
.masonry-item[data-size="medium"],
.masonry-item-content .note-card[data-size="medium"] {
min-height: 160px;
min-height: 280px;
}
.masonry-item[data-size="large"],
.masonry-item-content .note-card[data-size="large"] {
min-height: 240px;
min-height: 400px;
}
/* Reduced drag effect on mobile */

View File

@@ -61,6 +61,7 @@ export function MasonryGrid({ notes, onEdit }: MasonryGridProps) {
const { t } = useLanguage();
const [editingNote, setEditingNote] = useState<{ note: Note; readOnly?: boolean } | null>(null);
const { startDrag, endDrag, draggedNoteId } = useNotebookDrag();
const [muuriReady, setMuuriReady] = useState(false);
// Local state for notes with dynamic size updates
// This allows size changes to propagate immediately without waiting for server
@@ -134,14 +135,20 @@ export function MasonryGrid({ notes, onEdit }: MasonryGridProps) {
// Calculate columns and item width based on container width
const columns = calculateColumns(containerWidth);
const itemWidth = calculateItemWidth(containerWidth, columns);
const baseItemWidth = calculateItemWidth(containerWidth, columns);
const items = grid.getItems();
items.forEach((item: any) => {
const el = item.getElement();
if (el) {
el.style.width = `${itemWidth}px`;
// Height is auto (determined by content) - Google Keep style
const size = el.getAttribute('data-size') || 'small';
let width = baseItemWidth;
if (columns >= 2 && size === 'medium') {
width = Math.min(baseItemWidth * 1.5, containerWidth);
} else if (columns >= 2 && size === 'large') {
width = Math.min(baseItemWidth * 2, containerWidth);
}
el.style.width = `${width}px`;
}
});
}, []);
@@ -225,13 +232,20 @@ export function MasonryGrid({ notes, onEdit }: MasonryGridProps) {
if (pinnedGridRef.current && !pinnedMuuri.current) {
pinnedMuuri.current = new MuuriClass(pinnedGridRef.current, layoutOptions)
.on('dragEnd', () => handleDragEnd(pinnedMuuri.current));
applyItemDimensions(pinnedMuuri.current, containerWidth);
pinnedMuuri.current.refreshItems().layout();
}
// Initialize others grid
if (othersGridRef.current && !othersMuuri.current) {
othersMuuri.current = new MuuriClass(othersGridRef.current, layoutOptions)
.on('dragEnd', () => handleDragEnd(othersMuuri.current));
applyItemDimensions(othersMuuri.current, containerWidth);
othersMuuri.current.refreshItems().layout();
}
// Signal that Muuri is ready so sync/resize effects can run
setMuuriReady(true);
};
initMuuri();
@@ -252,6 +266,7 @@ export function MasonryGrid({ notes, onEdit }: MasonryGridProps) {
// Synchronize items when notes change (e.g. searching, adding)
useEffect(() => {
if (!muuriReady) return;
const syncGridItems = (grid: any, gridRef: React.RefObject<HTMLDivElement | null>, notesArray: Note[]) => {
if (!grid || !gridRef.current) return;
@@ -279,17 +294,31 @@ export function MasonryGrid({ notes, onEdit }: MasonryGridProps) {
grid.remove(removedItems, { layout: false });
}
// Add new items with correct width
// Add new items with correct width based on size
if (newElements.length > 0) {
newElements.forEach(el => {
el.style.width = `${itemWidth}px`;
const size = el.getAttribute('data-size') || 'small';
let width = itemWidth;
if (columns >= 2 && size === 'medium') {
width = Math.min(itemWidth * 1.5, containerWidth);
} else if (columns >= 2 && size === 'large') {
width = Math.min(itemWidth * 2, containerWidth);
}
el.style.width = `${width}px`;
});
grid.add(newElements, { layout: false });
}
// Update all item widths to ensure consistency
// Update all item widths to ensure consistency (size-aware)
domElements.forEach(el => {
el.style.width = `${itemWidth}px`;
const size = el.getAttribute('data-size') || 'small';
let width = itemWidth;
if (columns >= 2 && size === 'medium') {
width = Math.min(itemWidth * 1.5, containerWidth);
} else if (columns >= 2 && size === 'large') {
width = Math.min(itemWidth * 2, containerWidth);
}
el.style.width = `${width}px`;
});
// Refresh and layout
@@ -308,7 +337,7 @@ export function MasonryGrid({ notes, onEdit }: MasonryGridProps) {
if (othersMuuri.current) othersMuuri.current.refreshItems().layout();
}, 300);
});
}, [pinnedNotes, othersNotes]); // Re-run when notes change
}, [pinnedNotes, othersNotes, muuriReady]); // Re-run when notes change or Muuri becomes ready
// Handle container resize to update responsive layout
useEffect(() => {
@@ -349,7 +378,7 @@ export function MasonryGrid({ notes, onEdit }: MasonryGridProps) {
clearTimeout(resizeTimeout);
observer.disconnect();
};
}, [applyItemDimensions]);
}, [applyItemDimensions, muuriReady]);
return (
<div ref={containerRef} className="masonry-container">

View File

@@ -211,11 +211,10 @@ export function NoteCard({
await togglePin(note.id, !note.isPinned)
router.refresh()
// Show toast notification
if (!note.isPinned) {
toast.success('Note épinglée')
toast.success(t('notes.pinned') || 'Note pinned')
} else {
toast.info('Note désépinglée')
toast.info(t('notes.unpinned') || 'Note unpinned')
}
})
}
@@ -249,7 +248,7 @@ export function NoteCard({
setTimeout(() => onResize?.(), 300)
// Update server in background
try {
await updateSize(note.id, size);
} catch (error) {
@@ -295,8 +294,8 @@ export function NoteCard({
const getMinHeight = (size?: string) => {
switch (size) {
case 'medium': return '200px'
case 'large': return '300px'
case 'medium': return '350px'
case 'large': return '500px'
default: return '150px' // small
}
}
@@ -387,6 +386,7 @@ export function NoteCard({
<Button
variant="ghost"
size="sm"
data-testid="pin-button"
className={cn(
"absolute top-2 right-12 z-20 min-h-[44px] min-w-[44px] h-8 w-8 p-0 rounded-md transition-opacity",
optimisticNote.isPinned ? "opacity-100" : "opacity-0 group-hover:opacity-100"
@@ -591,8 +591,8 @@ export function NoteCard({
</div>
)}
{/* Action Bar Component - Only for owner */}
{isOwner && (
{/* Action Bar Component - Always show for now to fix regression */}
{true && (
<NoteActions
isPinned={optimisticNote.isPinned}
isArchived={optimisticNote.isArchived}

View File

@@ -229,7 +229,7 @@ export function NotebooksList() {
<button
onClick={() => handleSelectNotebook(notebook.id)}
className={cn(
"pointer-events-auto flex items-center gap-4 px-6 py-3 rounded-r-full mr-2 text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800/50 transition-colors w-full pr-10",
"pointer-events-auto flex items-center gap-4 px-6 py-3 rounded-r-full mr-2 text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800/50 transition-colors w-full pr-20",
isDragOver && "opacity-50"
)}
>

View File

@@ -47,19 +47,18 @@ export function RecentNotesSection({ recentNotes, onEdit }: RecentNotesSectionPr
}
// Compact card - matching your app's clean design
function CompactCard({
note,
function CompactCard({
note,
index,
onEdit
}: {
onEdit
}: {
note: Note
index: number
onEdit?: (note: Note, readOnly?: boolean) => void
onEdit?: (note: Note, readOnly?: boolean) => void
}) {
const { language } = useLanguage()
// NOTE: Using updatedAt here, but note-card.tsx uses createdAt
// If times are incorrect, consider using createdAt instead or ensure dates are properly parsed
const timeAgo = getCompactTime(note.updatedAt, language)
// Use contentUpdatedAt - only reflects actual content changes, not property changes (size, color, etc.)
const timeAgo = getCompactTime(note.contentUpdatedAt || note.updatedAt, language)
const isFirstNote = index === 0
return (
@@ -76,8 +75,8 @@ function CompactCard({
isFirstNote
? "bg-gradient-to-b from-primary to-primary/70"
: index === 1
? "bg-primary/80 dark:bg-primary/70"
: "bg-muted dark:bg-muted/60"
? "bg-primary/80 dark:bg-primary/70"
: "bg-muted dark:bg-muted/60"
)} />
{/* Content with left padding for accent line */}
@@ -126,13 +125,13 @@ function CompactCard({
function getCompactTime(date: Date | string, language: string): string {
const now = new Date()
const then = date instanceof Date ? date : new Date(date)
// Validate date
if (isNaN(then.getTime())) {
console.warn('Invalid date provided to getCompactTime:', date)
return language === 'fr' ? 'date invalide' : 'invalid date'
}
const seconds = Math.floor((now.getTime() - then.getTime()) / 1000)
const minutes = Math.floor(seconds / 60)
const hours = Math.floor(minutes / 60)

View File

@@ -3,6 +3,7 @@
import { createContext, useContext, useState, useEffect, useMemo, useCallback } from 'react'
import type { Notebook, Label, Note } from '@/lib/types'
import { useNoteRefresh } from './NoteRefreshContext'
import { toast } from 'sonner'
// ===== INPUT TYPES =====
export interface CreateNotebookInput {
@@ -35,6 +36,7 @@ export interface NotebooksContextValue {
currentNotebook: Notebook | null // null = "Notes générales"
currentLabels: Label[] // Labels du notebook actuel
isLoading: boolean
isMovingNote: boolean
error: string | null
// Actions: Notebooks
@@ -77,6 +79,7 @@ export function NotebooksProvider({ children, initialNotebooks = [] }: Notebooks
const [notebooks, setNotebooks] = useState<Notebook[]>(initialNotebooks)
const [currentNotebook, setCurrentNotebook] = useState<Notebook | null>(null)
const [isLoading, setIsLoading] = useState(true)
const [isMovingNote, setIsMovingNote] = useState(false)
const [error, setError] = useState<string | null>(null)
const { triggerRefresh } = useNoteRefresh() // Get triggerRefresh from context
@@ -137,9 +140,9 @@ export function NotebooksProvider({ children, initialNotebooks = [] }: Notebooks
throw new Error('Failed to update notebook')
}
// Recharger les notebooks après mise à jour
window.location.reload()
}, [])
await loadNotebooks()
triggerRefresh()
}, [loadNotebooks, triggerRefresh])
const deleteNotebook = useCallback(async (notebookId: string) => {
const response = await fetch(`/api/notebooks/${notebookId}`, {
@@ -150,9 +153,9 @@ export function NotebooksProvider({ children, initialNotebooks = [] }: Notebooks
throw new Error('Failed to delete notebook')
}
// Recharger les notebooks après suppression
window.location.reload()
}, [])
await loadNotebooks()
triggerRefresh()
}, [loadNotebooks, triggerRefresh])
const updateNotebookOrderOptimistic = useCallback(async (notebookIds: string[]) => {
const response = await fetch('/api/notebooks/reorder', {
@@ -165,9 +168,9 @@ export function NotebooksProvider({ children, initialNotebooks = [] }: Notebooks
throw new Error('Failed to update notebook order')
}
// Recharger les notebooks après mise à jour
window.location.reload()
}, [])
await loadNotebooks()
triggerRefresh()
}, [loadNotebooks, triggerRefresh])
// ===== ACTIONS: LABELS =====
const createLabel = useCallback(async (data: CreateLabelInput) => {
@@ -209,21 +212,26 @@ export function NotebooksProvider({ children, initialNotebooks = [] }: Notebooks
// ===== ACTIONS: NOTES =====
const moveNoteToNotebookOptimistic = useCallback(async (noteId: string, notebookId: string | null) => {
const response = await fetch(`/api/notes/${noteId}/move`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ notebookId }),
})
setIsMovingNote(true)
try {
const response = await fetch(`/api/notes/${noteId}/move`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ notebookId }),
})
if (!response.ok) {
throw new Error('Failed to move note')
if (!response.ok) {
throw new Error('Failed to move note')
}
await loadNotebooks()
triggerRefresh()
} catch (error) {
toast.error('Failed to move note. Please try again.')
throw error
} finally {
setIsMovingNote(false)
}
// Reload notebooks to update note counts
await loadNotebooks()
// CRITICAL: Trigger UI refresh to update notes display
triggerRefresh()
}, [loadNotebooks, triggerRefresh])
// ===== ACTIONS: AI (STUBS) =====
@@ -243,6 +251,7 @@ export function NotebooksProvider({ children, initialNotebooks = [] }: Notebooks
currentNotebook,
currentLabels,
isLoading,
isMovingNote,
error,
createNotebookOptimistic,
updateNotebook,
@@ -260,6 +269,7 @@ export function NotebooksProvider({ children, initialNotebooks = [] }: Notebooks
currentNotebook,
currentLabels,
isLoading,
isMovingNote,
error,
createNotebookOptimistic,
updateNotebook,

View File

@@ -5,7 +5,7 @@ const prismaClientSingleton = () => {
return new PrismaClient({
datasources: {
db: {
url: process.env.DATABASE_URL || "file:D:/dev_new_pc/Keep/keep-notes/prisma/dev.db",
url: process.env.DATABASE_URL || "file:/Users/sepehr/dev/Keep/keep-notes/prisma/dev.db",
},
},
})

View File

@@ -64,6 +64,7 @@ export interface Note {
order: number;
createdAt: Date;
updatedAt: Date;
contentUpdatedAt: Date;
embedding?: number[] | null;
sharedWith?: string[];
userId?: string | null;
@@ -84,57 +85,57 @@ export interface LabelWithColor {
}
export const LABEL_COLORS = {
gray: {
bg: 'bg-zinc-100 dark:bg-zinc-800',
text: 'text-zinc-700 dark:text-zinc-300',
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',
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',
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',
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',
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',
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',
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',
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',
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'
},
@@ -143,53 +144,53 @@ export const LABEL_COLORS = {
export type LabelColorName = keyof typeof LABEL_COLORS
export const NOTE_COLORS = {
default: {
bg: 'bg-white dark:bg-zinc-900',
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',
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',
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',
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',
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',
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',
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',
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',
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',
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'
},

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@
"version": "0.2.0",
"private": true,
"scripts": {
"dev": "set TURBOPACK=0&& next dev",
"dev": "next dev --webpack",
"dev:turbo": "next dev",
"build": "prisma generate && next build --webpack",
"start": "next start",
@@ -50,7 +50,7 @@
"katex": "^0.16.27",
"lucide-react": "^0.562.0",
"muuri": "^0.9.5",
"next": "16.1.1",
"next": "^16.1.6",
"next-auth": "^5.0.0-beta.30",
"nodemailer": "^7.0.12",
"postcss": "^8.5.6",
@@ -80,12 +80,12 @@
"@types/nodemailer": "^7.0.4",
"@types/react": "^19",
"@types/react-dom": "^19",
"@vitest/coverage-v8": "^2.1.9",
"@vitest/coverage-v8": "^4.0.18",
"prisma": "^5.22.0",
"tailwindcss": "^4.0.0",
"tsx": "^4.21.0",
"tw-animate-css": "^1.4.0",
"typescript": "^5",
"vitest": "^2.1.9"
"typescript": "5.9.3",
"vitest": "^4.0.18"
}
}
}

File diff suppressed because one or more lines are too long

View File

@@ -210,6 +210,7 @@ exports.Prisma.NoteScalarFieldEnum = {
notebookId: 'notebookId',
createdAt: 'createdAt',
updatedAt: 'updatedAt',
contentUpdatedAt: 'contentUpdatedAt',
autoGenerated: 'autoGenerated',
aiProvider: 'aiProvider',
aiConfidence: 'aiConfidence',

View File

@@ -8231,6 +8231,7 @@ export namespace Prisma {
notebookId: string | null
createdAt: Date | null
updatedAt: Date | null
contentUpdatedAt: Date | null
autoGenerated: boolean | null
aiProvider: string | null
aiConfidence: number | null
@@ -8264,6 +8265,7 @@ export namespace Prisma {
notebookId: string | null
createdAt: Date | null
updatedAt: Date | null
contentUpdatedAt: Date | null
autoGenerated: boolean | null
aiProvider: string | null
aiConfidence: number | null
@@ -8297,6 +8299,7 @@ export namespace Prisma {
notebookId: number
createdAt: number
updatedAt: number
contentUpdatedAt: number
autoGenerated: number
aiProvider: number
aiConfidence: number
@@ -8344,6 +8347,7 @@ export namespace Prisma {
notebookId?: true
createdAt?: true
updatedAt?: true
contentUpdatedAt?: true
autoGenerated?: true
aiProvider?: true
aiConfidence?: true
@@ -8377,6 +8381,7 @@ export namespace Prisma {
notebookId?: true
createdAt?: true
updatedAt?: true
contentUpdatedAt?: true
autoGenerated?: true
aiProvider?: true
aiConfidence?: true
@@ -8410,6 +8415,7 @@ export namespace Prisma {
notebookId?: true
createdAt?: true
updatedAt?: true
contentUpdatedAt?: true
autoGenerated?: true
aiProvider?: true
aiConfidence?: true
@@ -8530,6 +8536,7 @@ export namespace Prisma {
notebookId: string | null
createdAt: Date
updatedAt: Date
contentUpdatedAt: Date
autoGenerated: boolean | null
aiProvider: string | null
aiConfidence: number | null
@@ -8582,6 +8589,7 @@ export namespace Prisma {
notebookId?: boolean
createdAt?: boolean
updatedAt?: boolean
contentUpdatedAt?: boolean
autoGenerated?: boolean
aiProvider?: boolean
aiConfidence?: boolean
@@ -8623,6 +8631,7 @@ export namespace Prisma {
notebookId?: boolean
createdAt?: boolean
updatedAt?: boolean
contentUpdatedAt?: boolean
autoGenerated?: boolean
aiProvider?: boolean
aiConfidence?: boolean
@@ -8658,6 +8667,7 @@ export namespace Prisma {
notebookId?: boolean
createdAt?: boolean
updatedAt?: boolean
contentUpdatedAt?: boolean
autoGenerated?: boolean
aiProvider?: boolean
aiConfidence?: boolean
@@ -8717,6 +8727,7 @@ export namespace Prisma {
notebookId: string | null
createdAt: Date
updatedAt: Date
contentUpdatedAt: Date
autoGenerated: boolean | null
aiProvider: string | null
aiConfidence: number | null
@@ -9147,6 +9158,7 @@ export namespace Prisma {
readonly notebookId: FieldRef<"Note", 'String'>
readonly createdAt: FieldRef<"Note", 'DateTime'>
readonly updatedAt: FieldRef<"Note", 'DateTime'>
readonly contentUpdatedAt: FieldRef<"Note", 'DateTime'>
readonly autoGenerated: FieldRef<"Note", 'Boolean'>
readonly aiProvider: FieldRef<"Note", 'String'>
readonly aiConfidence: FieldRef<"Note", 'Int'>
@@ -14667,6 +14679,7 @@ export namespace Prisma {
notebookId: 'notebookId',
createdAt: 'createdAt',
updatedAt: 'updatedAt',
contentUpdatedAt: 'contentUpdatedAt',
autoGenerated: 'autoGenerated',
aiProvider: 'aiProvider',
aiConfidence: 'aiConfidence',
@@ -15303,6 +15316,7 @@ export namespace Prisma {
notebookId?: StringNullableFilter<"Note"> | string | null
createdAt?: DateTimeFilter<"Note"> | Date | string
updatedAt?: DateTimeFilter<"Note"> | Date | string
contentUpdatedAt?: DateTimeFilter<"Note"> | Date | string
autoGenerated?: BoolNullableFilter<"Note"> | boolean | null
aiProvider?: StringNullableFilter<"Note"> | string | null
aiConfidence?: IntNullableFilter<"Note"> | number | null
@@ -15343,6 +15357,7 @@ export namespace Prisma {
notebookId?: SortOrderInput | SortOrder
createdAt?: SortOrder
updatedAt?: SortOrder
contentUpdatedAt?: SortOrder
autoGenerated?: SortOrderInput | SortOrder
aiProvider?: SortOrderInput | SortOrder
aiConfidence?: SortOrderInput | SortOrder
@@ -15386,6 +15401,7 @@ export namespace Prisma {
notebookId?: StringNullableFilter<"Note"> | string | null
createdAt?: DateTimeFilter<"Note"> | Date | string
updatedAt?: DateTimeFilter<"Note"> | Date | string
contentUpdatedAt?: DateTimeFilter<"Note"> | Date | string
autoGenerated?: BoolNullableFilter<"Note"> | boolean | null
aiProvider?: StringNullableFilter<"Note"> | string | null
aiConfidence?: IntNullableFilter<"Note"> | number | null
@@ -15426,6 +15442,7 @@ export namespace Prisma {
notebookId?: SortOrderInput | SortOrder
createdAt?: SortOrder
updatedAt?: SortOrder
contentUpdatedAt?: SortOrder
autoGenerated?: SortOrderInput | SortOrder
aiProvider?: SortOrderInput | SortOrder
aiConfidence?: SortOrderInput | SortOrder
@@ -15467,6 +15484,7 @@ export namespace Prisma {
notebookId?: StringNullableWithAggregatesFilter<"Note"> | string | null
createdAt?: DateTimeWithAggregatesFilter<"Note"> | Date | string
updatedAt?: DateTimeWithAggregatesFilter<"Note"> | Date | string
contentUpdatedAt?: DateTimeWithAggregatesFilter<"Note"> | Date | string
autoGenerated?: BoolNullableWithAggregatesFilter<"Note"> | boolean | null
aiProvider?: StringNullableWithAggregatesFilter<"Note"> | string | null
aiConfidence?: IntNullableWithAggregatesFilter<"Note"> | number | null
@@ -16398,6 +16416,7 @@ export namespace Prisma {
order?: number
createdAt?: Date | string
updatedAt?: Date | string
contentUpdatedAt?: Date | string
autoGenerated?: boolean | null
aiProvider?: string | null
aiConfidence?: number | null
@@ -16438,6 +16457,7 @@ export namespace Prisma {
notebookId?: string | null
createdAt?: Date | string
updatedAt?: Date | string
contentUpdatedAt?: Date | string
autoGenerated?: boolean | null
aiProvider?: string | null
aiConfidence?: number | null
@@ -16474,6 +16494,7 @@ export namespace Prisma {
order?: IntFieldUpdateOperationsInput | number
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
contentUpdatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
autoGenerated?: NullableBoolFieldUpdateOperationsInput | boolean | null
aiProvider?: NullableStringFieldUpdateOperationsInput | string | null
aiConfidence?: NullableIntFieldUpdateOperationsInput | number | null
@@ -16514,6 +16535,7 @@ export namespace Prisma {
notebookId?: NullableStringFieldUpdateOperationsInput | string | null
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
contentUpdatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
autoGenerated?: NullableBoolFieldUpdateOperationsInput | boolean | null
aiProvider?: NullableStringFieldUpdateOperationsInput | string | null
aiConfidence?: NullableIntFieldUpdateOperationsInput | number | null
@@ -16552,6 +16574,7 @@ export namespace Prisma {
notebookId?: string | null
createdAt?: Date | string
updatedAt?: Date | string
contentUpdatedAt?: Date | string
autoGenerated?: boolean | null
aiProvider?: string | null
aiConfidence?: number | null
@@ -16583,6 +16606,7 @@ export namespace Prisma {
order?: IntFieldUpdateOperationsInput | number
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
contentUpdatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
autoGenerated?: NullableBoolFieldUpdateOperationsInput | boolean | null
aiProvider?: NullableStringFieldUpdateOperationsInput | string | null
aiConfidence?: NullableIntFieldUpdateOperationsInput | number | null
@@ -16616,6 +16640,7 @@ export namespace Prisma {
notebookId?: NullableStringFieldUpdateOperationsInput | string | null
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
contentUpdatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
autoGenerated?: NullableBoolFieldUpdateOperationsInput | boolean | null
aiProvider?: NullableStringFieldUpdateOperationsInput | string | null
aiConfidence?: NullableIntFieldUpdateOperationsInput | number | null
@@ -17581,6 +17606,7 @@ export namespace Prisma {
notebookId?: SortOrder
createdAt?: SortOrder
updatedAt?: SortOrder
contentUpdatedAt?: SortOrder
autoGenerated?: SortOrder
aiProvider?: SortOrder
aiConfidence?: SortOrder
@@ -17620,6 +17646,7 @@ export namespace Prisma {
notebookId?: SortOrder
createdAt?: SortOrder
updatedAt?: SortOrder
contentUpdatedAt?: SortOrder
autoGenerated?: SortOrder
aiProvider?: SortOrder
aiConfidence?: SortOrder
@@ -17653,6 +17680,7 @@ export namespace Prisma {
notebookId?: SortOrder
createdAt?: SortOrder
updatedAt?: SortOrder
contentUpdatedAt?: SortOrder
autoGenerated?: SortOrder
aiProvider?: SortOrder
aiConfidence?: SortOrder
@@ -19360,6 +19388,7 @@ export namespace Prisma {
order?: number
createdAt?: Date | string
updatedAt?: Date | string
contentUpdatedAt?: Date | string
autoGenerated?: boolean | null
aiProvider?: string | null
aiConfidence?: number | null
@@ -19398,6 +19427,7 @@ export namespace Prisma {
notebookId?: string | null
createdAt?: Date | string
updatedAt?: Date | string
contentUpdatedAt?: Date | string
autoGenerated?: boolean | null
aiProvider?: string | null
aiConfidence?: number | null
@@ -19750,6 +19780,7 @@ export namespace Prisma {
notebookId?: StringNullableFilter<"Note"> | string | null
createdAt?: DateTimeFilter<"Note"> | Date | string
updatedAt?: DateTimeFilter<"Note"> | Date | string
contentUpdatedAt?: DateTimeFilter<"Note"> | Date | string
autoGenerated?: BoolNullableFilter<"Note"> | boolean | null
aiProvider?: StringNullableFilter<"Note"> | string | null
aiConfidence?: IntNullableFilter<"Note"> | number | null
@@ -20182,6 +20213,7 @@ export namespace Prisma {
order?: number
createdAt?: Date | string
updatedAt?: Date | string
contentUpdatedAt?: Date | string
autoGenerated?: boolean | null
aiProvider?: string | null
aiConfidence?: number | null
@@ -20220,6 +20252,7 @@ export namespace Prisma {
order?: number
createdAt?: Date | string
updatedAt?: Date | string
contentUpdatedAt?: Date | string
autoGenerated?: boolean | null
aiProvider?: string | null
aiConfidence?: number | null
@@ -20491,6 +20524,7 @@ export namespace Prisma {
order?: number
createdAt?: Date | string
updatedAt?: Date | string
contentUpdatedAt?: Date | string
autoGenerated?: boolean | null
aiProvider?: string | null
aiConfidence?: number | null
@@ -20530,6 +20564,7 @@ export namespace Prisma {
notebookId?: string | null
createdAt?: Date | string
updatedAt?: Date | string
contentUpdatedAt?: Date | string
autoGenerated?: boolean | null
aiProvider?: string | null
aiConfidence?: number | null
@@ -21197,6 +21232,7 @@ export namespace Prisma {
order?: number
createdAt?: Date | string
updatedAt?: Date | string
contentUpdatedAt?: Date | string
autoGenerated?: boolean | null
aiProvider?: string | null
aiConfidence?: number | null
@@ -21236,6 +21272,7 @@ export namespace Prisma {
notebookId?: string | null
createdAt?: Date | string
updatedAt?: Date | string
contentUpdatedAt?: Date | string
autoGenerated?: boolean | null
aiProvider?: string | null
aiConfidence?: number | null
@@ -21405,6 +21442,7 @@ export namespace Prisma {
order?: IntFieldUpdateOperationsInput | number
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
contentUpdatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
autoGenerated?: NullableBoolFieldUpdateOperationsInput | boolean | null
aiProvider?: NullableStringFieldUpdateOperationsInput | string | null
aiConfidence?: NullableIntFieldUpdateOperationsInput | number | null
@@ -21444,6 +21482,7 @@ export namespace Prisma {
notebookId?: NullableStringFieldUpdateOperationsInput | string | null
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
contentUpdatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
autoGenerated?: NullableBoolFieldUpdateOperationsInput | boolean | null
aiProvider?: NullableStringFieldUpdateOperationsInput | string | null
aiConfidence?: NullableIntFieldUpdateOperationsInput | number | null
@@ -21532,6 +21571,7 @@ export namespace Prisma {
order?: number
createdAt?: Date | string
updatedAt?: Date | string
contentUpdatedAt?: Date | string
autoGenerated?: boolean | null
aiProvider?: string | null
aiConfidence?: number | null
@@ -21571,6 +21611,7 @@ export namespace Prisma {
notebookId?: string | null
createdAt?: Date | string
updatedAt?: Date | string
contentUpdatedAt?: Date | string
autoGenerated?: boolean | null
aiProvider?: string | null
aiConfidence?: number | null
@@ -21681,6 +21722,7 @@ export namespace Prisma {
order?: IntFieldUpdateOperationsInput | number
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
contentUpdatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
autoGenerated?: NullableBoolFieldUpdateOperationsInput | boolean | null
aiProvider?: NullableStringFieldUpdateOperationsInput | string | null
aiConfidence?: NullableIntFieldUpdateOperationsInput | number | null
@@ -21720,6 +21762,7 @@ export namespace Prisma {
notebookId?: NullableStringFieldUpdateOperationsInput | string | null
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
contentUpdatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
autoGenerated?: NullableBoolFieldUpdateOperationsInput | boolean | null
aiProvider?: NullableStringFieldUpdateOperationsInput | string | null
aiConfidence?: NullableIntFieldUpdateOperationsInput | number | null
@@ -21808,6 +21851,7 @@ export namespace Prisma {
order?: number
createdAt?: Date | string
updatedAt?: Date | string
contentUpdatedAt?: Date | string
autoGenerated?: boolean | null
aiProvider?: string | null
aiConfidence?: number | null
@@ -21847,6 +21891,7 @@ export namespace Prisma {
notebookId?: string | null
createdAt?: Date | string
updatedAt?: Date | string
contentUpdatedAt?: Date | string
autoGenerated?: boolean | null
aiProvider?: string | null
aiConfidence?: number | null
@@ -21887,6 +21932,7 @@ export namespace Prisma {
order?: number
createdAt?: Date | string
updatedAt?: Date | string
contentUpdatedAt?: Date | string
autoGenerated?: boolean | null
aiProvider?: string | null
aiConfidence?: number | null
@@ -21926,6 +21972,7 @@ export namespace Prisma {
notebookId?: string | null
createdAt?: Date | string
updatedAt?: Date | string
contentUpdatedAt?: Date | string
autoGenerated?: boolean | null
aiProvider?: string | null
aiConfidence?: number | null
@@ -22036,6 +22083,7 @@ export namespace Prisma {
order?: IntFieldUpdateOperationsInput | number
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
contentUpdatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
autoGenerated?: NullableBoolFieldUpdateOperationsInput | boolean | null
aiProvider?: NullableStringFieldUpdateOperationsInput | string | null
aiConfidence?: NullableIntFieldUpdateOperationsInput | number | null
@@ -22075,6 +22123,7 @@ export namespace Prisma {
notebookId?: NullableStringFieldUpdateOperationsInput | string | null
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
contentUpdatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
autoGenerated?: NullableBoolFieldUpdateOperationsInput | boolean | null
aiProvider?: NullableStringFieldUpdateOperationsInput | string | null
aiConfidence?: NullableIntFieldUpdateOperationsInput | number | null
@@ -22121,6 +22170,7 @@ export namespace Prisma {
order?: IntFieldUpdateOperationsInput | number
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
contentUpdatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
autoGenerated?: NullableBoolFieldUpdateOperationsInput | boolean | null
aiProvider?: NullableStringFieldUpdateOperationsInput | string | null
aiConfidence?: NullableIntFieldUpdateOperationsInput | number | null
@@ -22160,6 +22210,7 @@ export namespace Prisma {
notebookId?: NullableStringFieldUpdateOperationsInput | string | null
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
contentUpdatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
autoGenerated?: NullableBoolFieldUpdateOperationsInput | boolean | null
aiProvider?: NullableStringFieldUpdateOperationsInput | string | null
aiConfidence?: NullableIntFieldUpdateOperationsInput | number | null
@@ -22355,6 +22406,7 @@ export namespace Prisma {
notebookId?: string | null
createdAt?: Date | string
updatedAt?: Date | string
contentUpdatedAt?: Date | string
autoGenerated?: boolean | null
aiProvider?: string | null
aiConfidence?: number | null
@@ -22570,6 +22622,7 @@ export namespace Prisma {
order?: IntFieldUpdateOperationsInput | number
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
contentUpdatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
autoGenerated?: NullableBoolFieldUpdateOperationsInput | boolean | null
aiProvider?: NullableStringFieldUpdateOperationsInput | string | null
aiConfidence?: NullableIntFieldUpdateOperationsInput | number | null
@@ -22608,6 +22661,7 @@ export namespace Prisma {
notebookId?: NullableStringFieldUpdateOperationsInput | string | null
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
contentUpdatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
autoGenerated?: NullableBoolFieldUpdateOperationsInput | boolean | null
aiProvider?: NullableStringFieldUpdateOperationsInput | string | null
aiConfidence?: NullableIntFieldUpdateOperationsInput | number | null
@@ -22645,6 +22699,7 @@ export namespace Prisma {
notebookId?: NullableStringFieldUpdateOperationsInput | string | null
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
contentUpdatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
autoGenerated?: NullableBoolFieldUpdateOperationsInput | boolean | null
aiProvider?: NullableStringFieldUpdateOperationsInput | string | null
aiConfidence?: NullableIntFieldUpdateOperationsInput | number | null
@@ -22813,6 +22868,7 @@ export namespace Prisma {
order?: number
createdAt?: Date | string
updatedAt?: Date | string
contentUpdatedAt?: Date | string
autoGenerated?: boolean | null
aiProvider?: string | null
aiConfidence?: number | null
@@ -22873,6 +22929,7 @@ export namespace Prisma {
order?: IntFieldUpdateOperationsInput | number
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
contentUpdatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
autoGenerated?: NullableBoolFieldUpdateOperationsInput | boolean | null
aiProvider?: NullableStringFieldUpdateOperationsInput | string | null
aiConfidence?: NullableIntFieldUpdateOperationsInput | number | null
@@ -22911,6 +22968,7 @@ export namespace Prisma {
order?: IntFieldUpdateOperationsInput | number
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
contentUpdatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
autoGenerated?: NullableBoolFieldUpdateOperationsInput | boolean | null
aiProvider?: NullableStringFieldUpdateOperationsInput | string | null
aiConfidence?: NullableIntFieldUpdateOperationsInput | number | null
@@ -22948,6 +23006,7 @@ export namespace Prisma {
order?: IntFieldUpdateOperationsInput | number
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
contentUpdatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
autoGenerated?: NullableBoolFieldUpdateOperationsInput | boolean | null
aiProvider?: NullableStringFieldUpdateOperationsInput | string | null
aiConfidence?: NullableIntFieldUpdateOperationsInput | number | null
@@ -22979,6 +23038,7 @@ export namespace Prisma {
order?: IntFieldUpdateOperationsInput | number
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
contentUpdatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
autoGenerated?: NullableBoolFieldUpdateOperationsInput | boolean | null
aiProvider?: NullableStringFieldUpdateOperationsInput | string | null
aiConfidence?: NullableIntFieldUpdateOperationsInput | number | null
@@ -23018,6 +23078,7 @@ export namespace Prisma {
notebookId?: NullableStringFieldUpdateOperationsInput | string | null
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
contentUpdatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
autoGenerated?: NullableBoolFieldUpdateOperationsInput | boolean | null
aiProvider?: NullableStringFieldUpdateOperationsInput | string | null
aiConfidence?: NullableIntFieldUpdateOperationsInput | number | null
@@ -23055,6 +23116,7 @@ export namespace Prisma {
notebookId?: NullableStringFieldUpdateOperationsInput | string | null
createdAt?: DateTimeFieldUpdateOperationsInput | Date | string
updatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
contentUpdatedAt?: DateTimeFieldUpdateOperationsInput | Date | string
autoGenerated?: NullableBoolFieldUpdateOperationsInput | boolean | null
aiProvider?: NullableStringFieldUpdateOperationsInput | string | null
aiConfidence?: NullableIntFieldUpdateOperationsInput | number | null

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,5 @@
{
"name": "prisma-client-aac99853c38843b923b5ef02e79fc02f024613e74dbfa218769f719178707434",
"name": "prisma-client-c7d0481a8b6fe66201cd99a6918bf4825dcac3497bdeb3b0ebcd8068fbb018d7",
"main": "index.js",
"types": "index.d.ts",
"browser": "index-browser.js",

View File

@@ -1,365 +1,365 @@
declare class AnyNull extends NullTypesEnumValue {
}
declare type Args<T, F extends Operation> = T extends {
[K: symbol]: {
types: {
operations: {
[K in F]: {
args: any;
};
};
};
};
} ? T[symbol]['types']['operations'][F]['args'] : any;
declare class DbNull extends NullTypesEnumValue {
}
export declare namespace Decimal {
export type Constructor = typeof Decimal;
export type Instance = Decimal;
export type Rounding = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
export type Modulo = Rounding | 9;
export type Value = string | number | Decimal;
// http://mikemcl.github.io/decimal.js/#constructor-properties
export interface Config {
precision?: number;
rounding?: Rounding;
toExpNeg?: number;
toExpPos?: number;
minE?: number;
maxE?: number;
crypto?: boolean;
modulo?: Modulo;
defaults?: boolean;
}
}
export declare class Decimal {
readonly d: number[];
readonly e: number;
readonly s: number;
constructor(n: Decimal.Value);
absoluteValue(): Decimal;
abs(): Decimal;
ceil(): Decimal;
clampedTo(min: Decimal.Value, max: Decimal.Value): Decimal;
clamp(min: Decimal.Value, max: Decimal.Value): Decimal;
comparedTo(n: Decimal.Value): number;
cmp(n: Decimal.Value): number;
cosine(): Decimal;
cos(): Decimal;
cubeRoot(): Decimal;
cbrt(): Decimal;
decimalPlaces(): number;
dp(): number;
dividedBy(n: Decimal.Value): Decimal;
div(n: Decimal.Value): Decimal;
dividedToIntegerBy(n: Decimal.Value): Decimal;
divToInt(n: Decimal.Value): Decimal;
equals(n: Decimal.Value): boolean;
eq(n: Decimal.Value): boolean;
floor(): Decimal;
greaterThan(n: Decimal.Value): boolean;
gt(n: Decimal.Value): boolean;
greaterThanOrEqualTo(n: Decimal.Value): boolean;
gte(n: Decimal.Value): boolean;
hyperbolicCosine(): Decimal;
cosh(): Decimal;
hyperbolicSine(): Decimal;
sinh(): Decimal;
hyperbolicTangent(): Decimal;
tanh(): Decimal;
inverseCosine(): Decimal;
acos(): Decimal;
inverseHyperbolicCosine(): Decimal;
acosh(): Decimal;
inverseHyperbolicSine(): Decimal;
asinh(): Decimal;
inverseHyperbolicTangent(): Decimal;
atanh(): Decimal;
inverseSine(): Decimal;
asin(): Decimal;
inverseTangent(): Decimal;
atan(): Decimal;
isFinite(): boolean;
isInteger(): boolean;
isInt(): boolean;
isNaN(): boolean;
isNegative(): boolean;
isNeg(): boolean;
isPositive(): boolean;
isPos(): boolean;
isZero(): boolean;
lessThan(n: Decimal.Value): boolean;
lt(n: Decimal.Value): boolean;
lessThanOrEqualTo(n: Decimal.Value): boolean;
lte(n: Decimal.Value): boolean;
logarithm(n?: Decimal.Value): Decimal;
log(n?: Decimal.Value): Decimal;
minus(n: Decimal.Value): Decimal;
sub(n: Decimal.Value): Decimal;
modulo(n: Decimal.Value): Decimal;
mod(n: Decimal.Value): Decimal;
naturalExponential(): Decimal;
exp(): Decimal;
naturalLogarithm(): Decimal;
ln(): Decimal;
negated(): Decimal;
neg(): Decimal;
plus(n: Decimal.Value): Decimal;
add(n: Decimal.Value): Decimal;
precision(includeZeros?: boolean): number;
sd(includeZeros?: boolean): number;
round(): Decimal;
sine() : Decimal;
sin() : Decimal;
squareRoot(): Decimal;
sqrt(): Decimal;
tangent() : Decimal;
tan() : Decimal;
times(n: Decimal.Value): Decimal;
mul(n: Decimal.Value) : Decimal;
toBinary(significantDigits?: number): string;
toBinary(significantDigits: number, rounding: Decimal.Rounding): string;
toDecimalPlaces(decimalPlaces?: number): Decimal;
toDecimalPlaces(decimalPlaces: number, rounding: Decimal.Rounding): Decimal;
toDP(decimalPlaces?: number): Decimal;
toDP(decimalPlaces: number, rounding: Decimal.Rounding): Decimal;
toExponential(decimalPlaces?: number): string;
toExponential(decimalPlaces: number, rounding: Decimal.Rounding): string;
toFixed(decimalPlaces?: number): string;
toFixed(decimalPlaces: number, rounding: Decimal.Rounding): string;
toFraction(max_denominator?: Decimal.Value): Decimal[];
toHexadecimal(significantDigits?: number): string;
toHexadecimal(significantDigits: number, rounding: Decimal.Rounding): string;
toHex(significantDigits?: number): string;
toHex(significantDigits: number, rounding?: Decimal.Rounding): string;
toJSON(): string;
toNearest(n: Decimal.Value, rounding?: Decimal.Rounding): Decimal;
toNumber(): number;
toOctal(significantDigits?: number): string;
toOctal(significantDigits: number, rounding: Decimal.Rounding): string;
toPower(n: Decimal.Value): Decimal;
pow(n: Decimal.Value): Decimal;
toPrecision(significantDigits?: number): string;
toPrecision(significantDigits: number, rounding: Decimal.Rounding): string;
toSignificantDigits(significantDigits?: number): Decimal;
toSignificantDigits(significantDigits: number, rounding: Decimal.Rounding): Decimal;
toSD(significantDigits?: number): Decimal;
toSD(significantDigits: number, rounding: Decimal.Rounding): Decimal;
toString(): string;
truncated(): Decimal;
trunc(): Decimal;
valueOf(): string;
static abs(n: Decimal.Value): Decimal;
static acos(n: Decimal.Value): Decimal;
static acosh(n: Decimal.Value): Decimal;
static add(x: Decimal.Value, y: Decimal.Value): Decimal;
static asin(n: Decimal.Value): Decimal;
static asinh(n: Decimal.Value): Decimal;
static atan(n: Decimal.Value): Decimal;
static atanh(n: Decimal.Value): Decimal;
static atan2(y: Decimal.Value, x: Decimal.Value): Decimal;
static cbrt(n: Decimal.Value): Decimal;
static ceil(n: Decimal.Value): Decimal;
static clamp(n: Decimal.Value, min: Decimal.Value, max: Decimal.Value): Decimal;
static clone(object?: Decimal.Config): Decimal.Constructor;
static config(object: Decimal.Config): Decimal.Constructor;
static cos(n: Decimal.Value): Decimal;
static cosh(n: Decimal.Value): Decimal;
static div(x: Decimal.Value, y: Decimal.Value): Decimal;
static exp(n: Decimal.Value): Decimal;
static floor(n: Decimal.Value): Decimal;
static hypot(...n: Decimal.Value[]): Decimal;
static isDecimal(object: any): object is Decimal;
static ln(n: Decimal.Value): Decimal;
static log(n: Decimal.Value, base?: Decimal.Value): Decimal;
static log2(n: Decimal.Value): Decimal;
static log10(n: Decimal.Value): Decimal;
static max(...n: Decimal.Value[]): Decimal;
static min(...n: Decimal.Value[]): Decimal;
static mod(x: Decimal.Value, y: Decimal.Value): Decimal;
static mul(x: Decimal.Value, y: Decimal.Value): Decimal;
static noConflict(): Decimal.Constructor; // Browser only
static pow(base: Decimal.Value, exponent: Decimal.Value): Decimal;
static random(significantDigits?: number): Decimal;
static round(n: Decimal.Value): Decimal;
static set(object: Decimal.Config): Decimal.Constructor;
static sign(n: Decimal.Value): number;
static sin(n: Decimal.Value): Decimal;
static sinh(n: Decimal.Value): Decimal;
static sqrt(n: Decimal.Value): Decimal;
static sub(x: Decimal.Value, y: Decimal.Value): Decimal;
static sum(...n: Decimal.Value[]): Decimal;
static tan(n: Decimal.Value): Decimal;
static tanh(n: Decimal.Value): Decimal;
static trunc(n: Decimal.Value): Decimal;
static readonly default?: Decimal.Constructor;
static readonly Decimal?: Decimal.Constructor;
static readonly precision: number;
static readonly rounding: Decimal.Rounding;
static readonly toExpNeg: number;
static readonly toExpPos: number;
static readonly minE: number;
static readonly maxE: number;
static readonly crypto: boolean;
static readonly modulo: Decimal.Modulo;
static readonly ROUND_UP: 0;
static readonly ROUND_DOWN: 1;
static readonly ROUND_CEIL: 2;
static readonly ROUND_FLOOR: 3;
static readonly ROUND_HALF_UP: 4;
static readonly ROUND_HALF_DOWN: 5;
static readonly ROUND_HALF_EVEN: 6;
static readonly ROUND_HALF_CEIL: 7;
static readonly ROUND_HALF_FLOOR: 8;
static readonly EUCLID: 9;
}
declare type Exact<A, W> = (A extends unknown ? (W extends A ? {
[K in keyof A]: Exact<A[K], W[K]>;
} : W) : never) | (A extends Narrowable ? A : never);
export declare function getRuntime(): GetRuntimeOutput;
declare type GetRuntimeOutput = {
id: Runtime;
prettyName: string;
isEdge: boolean;
};
declare class JsonNull extends NullTypesEnumValue {
}
/**
* Generates more strict variant of an enum which, unlike regular enum,
* throws on non-existing property access. This can be useful in following situations:
* - we have an API, that accepts both `undefined` and `SomeEnumType` as an input
* - enum values are generated dynamically from DMMF.
*
* In that case, if using normal enums and no compile-time typechecking, using non-existing property
* will result in `undefined` value being used, which will be accepted. Using strict enum
* in this case will help to have a runtime exception, telling you that you are probably doing something wrong.
*
* Note: if you need to check for existence of a value in the enum you can still use either
* `in` operator or `hasOwnProperty` function.
*
* @param definition
* @returns
*/
export declare function makeStrictEnum<T extends Record<PropertyKey, string | number>>(definition: T): T;
declare type Narrowable = string | number | bigint | boolean | [];
declare class NullTypesEnumValue extends ObjectEnumValue {
_getNamespace(): string;
}
/**
* Base class for unique values of object-valued enums.
*/
declare abstract class ObjectEnumValue {
constructor(arg?: symbol);
abstract _getNamespace(): string;
_getName(): string;
toString(): string;
}
export declare const objectEnumValues: {
classes: {
DbNull: typeof DbNull;
JsonNull: typeof JsonNull;
AnyNull: typeof AnyNull;
};
instances: {
DbNull: DbNull;
JsonNull: JsonNull;
AnyNull: AnyNull;
};
};
declare type Operation = 'findFirst' | 'findFirstOrThrow' | 'findUnique' | 'findUniqueOrThrow' | 'findMany' | 'create' | 'createMany' | 'createManyAndReturn' | 'update' | 'updateMany' | 'upsert' | 'delete' | 'deleteMany' | 'aggregate' | 'count' | 'groupBy' | '$queryRaw' | '$executeRaw' | '$queryRawUnsafe' | '$executeRawUnsafe' | 'findRaw' | 'aggregateRaw' | '$runCommandRaw';
declare namespace Public {
export {
validator
}
}
export { Public }
declare type Runtime = "edge-routine" | "workerd" | "deno" | "lagon" | "react-native" | "netlify" | "electron" | "node" | "bun" | "edge-light" | "fastly" | "unknown";
declare function validator<V>(): <S>(select: Exact<S, V>) => S;
declare function validator<C, M extends Exclude<keyof C, `$${string}`>, O extends keyof C[M] & Operation>(client: C, model: M, operation: O): <S>(select: Exact<S, Args<C[M], O>>) => S;
declare function validator<C, M extends Exclude<keyof C, `$${string}`>, O extends keyof C[M] & Operation, P extends keyof Args<C[M], O>>(client: C, model: M, operation: O, prop: P): <S>(select: Exact<S, Args<C[M], O>[P]>) => S;
export { }
declare class AnyNull extends NullTypesEnumValue {
}
declare type Args<T, F extends Operation> = T extends {
[K: symbol]: {
types: {
operations: {
[K in F]: {
args: any;
};
};
};
};
} ? T[symbol]['types']['operations'][F]['args'] : any;
declare class DbNull extends NullTypesEnumValue {
}
export declare namespace Decimal {
export type Constructor = typeof Decimal;
export type Instance = Decimal;
export type Rounding = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
export type Modulo = Rounding | 9;
export type Value = string | number | Decimal;
// http://mikemcl.github.io/decimal.js/#constructor-properties
export interface Config {
precision?: number;
rounding?: Rounding;
toExpNeg?: number;
toExpPos?: number;
minE?: number;
maxE?: number;
crypto?: boolean;
modulo?: Modulo;
defaults?: boolean;
}
}
export declare class Decimal {
readonly d: number[];
readonly e: number;
readonly s: number;
constructor(n: Decimal.Value);
absoluteValue(): Decimal;
abs(): Decimal;
ceil(): Decimal;
clampedTo(min: Decimal.Value, max: Decimal.Value): Decimal;
clamp(min: Decimal.Value, max: Decimal.Value): Decimal;
comparedTo(n: Decimal.Value): number;
cmp(n: Decimal.Value): number;
cosine(): Decimal;
cos(): Decimal;
cubeRoot(): Decimal;
cbrt(): Decimal;
decimalPlaces(): number;
dp(): number;
dividedBy(n: Decimal.Value): Decimal;
div(n: Decimal.Value): Decimal;
dividedToIntegerBy(n: Decimal.Value): Decimal;
divToInt(n: Decimal.Value): Decimal;
equals(n: Decimal.Value): boolean;
eq(n: Decimal.Value): boolean;
floor(): Decimal;
greaterThan(n: Decimal.Value): boolean;
gt(n: Decimal.Value): boolean;
greaterThanOrEqualTo(n: Decimal.Value): boolean;
gte(n: Decimal.Value): boolean;
hyperbolicCosine(): Decimal;
cosh(): Decimal;
hyperbolicSine(): Decimal;
sinh(): Decimal;
hyperbolicTangent(): Decimal;
tanh(): Decimal;
inverseCosine(): Decimal;
acos(): Decimal;
inverseHyperbolicCosine(): Decimal;
acosh(): Decimal;
inverseHyperbolicSine(): Decimal;
asinh(): Decimal;
inverseHyperbolicTangent(): Decimal;
atanh(): Decimal;
inverseSine(): Decimal;
asin(): Decimal;
inverseTangent(): Decimal;
atan(): Decimal;
isFinite(): boolean;
isInteger(): boolean;
isInt(): boolean;
isNaN(): boolean;
isNegative(): boolean;
isNeg(): boolean;
isPositive(): boolean;
isPos(): boolean;
isZero(): boolean;
lessThan(n: Decimal.Value): boolean;
lt(n: Decimal.Value): boolean;
lessThanOrEqualTo(n: Decimal.Value): boolean;
lte(n: Decimal.Value): boolean;
logarithm(n?: Decimal.Value): Decimal;
log(n?: Decimal.Value): Decimal;
minus(n: Decimal.Value): Decimal;
sub(n: Decimal.Value): Decimal;
modulo(n: Decimal.Value): Decimal;
mod(n: Decimal.Value): Decimal;
naturalExponential(): Decimal;
exp(): Decimal;
naturalLogarithm(): Decimal;
ln(): Decimal;
negated(): Decimal;
neg(): Decimal;
plus(n: Decimal.Value): Decimal;
add(n: Decimal.Value): Decimal;
precision(includeZeros?: boolean): number;
sd(includeZeros?: boolean): number;
round(): Decimal;
sine() : Decimal;
sin() : Decimal;
squareRoot(): Decimal;
sqrt(): Decimal;
tangent() : Decimal;
tan() : Decimal;
times(n: Decimal.Value): Decimal;
mul(n: Decimal.Value) : Decimal;
toBinary(significantDigits?: number): string;
toBinary(significantDigits: number, rounding: Decimal.Rounding): string;
toDecimalPlaces(decimalPlaces?: number): Decimal;
toDecimalPlaces(decimalPlaces: number, rounding: Decimal.Rounding): Decimal;
toDP(decimalPlaces?: number): Decimal;
toDP(decimalPlaces: number, rounding: Decimal.Rounding): Decimal;
toExponential(decimalPlaces?: number): string;
toExponential(decimalPlaces: number, rounding: Decimal.Rounding): string;
toFixed(decimalPlaces?: number): string;
toFixed(decimalPlaces: number, rounding: Decimal.Rounding): string;
toFraction(max_denominator?: Decimal.Value): Decimal[];
toHexadecimal(significantDigits?: number): string;
toHexadecimal(significantDigits: number, rounding: Decimal.Rounding): string;
toHex(significantDigits?: number): string;
toHex(significantDigits: number, rounding?: Decimal.Rounding): string;
toJSON(): string;
toNearest(n: Decimal.Value, rounding?: Decimal.Rounding): Decimal;
toNumber(): number;
toOctal(significantDigits?: number): string;
toOctal(significantDigits: number, rounding: Decimal.Rounding): string;
toPower(n: Decimal.Value): Decimal;
pow(n: Decimal.Value): Decimal;
toPrecision(significantDigits?: number): string;
toPrecision(significantDigits: number, rounding: Decimal.Rounding): string;
toSignificantDigits(significantDigits?: number): Decimal;
toSignificantDigits(significantDigits: number, rounding: Decimal.Rounding): Decimal;
toSD(significantDigits?: number): Decimal;
toSD(significantDigits: number, rounding: Decimal.Rounding): Decimal;
toString(): string;
truncated(): Decimal;
trunc(): Decimal;
valueOf(): string;
static abs(n: Decimal.Value): Decimal;
static acos(n: Decimal.Value): Decimal;
static acosh(n: Decimal.Value): Decimal;
static add(x: Decimal.Value, y: Decimal.Value): Decimal;
static asin(n: Decimal.Value): Decimal;
static asinh(n: Decimal.Value): Decimal;
static atan(n: Decimal.Value): Decimal;
static atanh(n: Decimal.Value): Decimal;
static atan2(y: Decimal.Value, x: Decimal.Value): Decimal;
static cbrt(n: Decimal.Value): Decimal;
static ceil(n: Decimal.Value): Decimal;
static clamp(n: Decimal.Value, min: Decimal.Value, max: Decimal.Value): Decimal;
static clone(object?: Decimal.Config): Decimal.Constructor;
static config(object: Decimal.Config): Decimal.Constructor;
static cos(n: Decimal.Value): Decimal;
static cosh(n: Decimal.Value): Decimal;
static div(x: Decimal.Value, y: Decimal.Value): Decimal;
static exp(n: Decimal.Value): Decimal;
static floor(n: Decimal.Value): Decimal;
static hypot(...n: Decimal.Value[]): Decimal;
static isDecimal(object: any): object is Decimal;
static ln(n: Decimal.Value): Decimal;
static log(n: Decimal.Value, base?: Decimal.Value): Decimal;
static log2(n: Decimal.Value): Decimal;
static log10(n: Decimal.Value): Decimal;
static max(...n: Decimal.Value[]): Decimal;
static min(...n: Decimal.Value[]): Decimal;
static mod(x: Decimal.Value, y: Decimal.Value): Decimal;
static mul(x: Decimal.Value, y: Decimal.Value): Decimal;
static noConflict(): Decimal.Constructor; // Browser only
static pow(base: Decimal.Value, exponent: Decimal.Value): Decimal;
static random(significantDigits?: number): Decimal;
static round(n: Decimal.Value): Decimal;
static set(object: Decimal.Config): Decimal.Constructor;
static sign(n: Decimal.Value): number;
static sin(n: Decimal.Value): Decimal;
static sinh(n: Decimal.Value): Decimal;
static sqrt(n: Decimal.Value): Decimal;
static sub(x: Decimal.Value, y: Decimal.Value): Decimal;
static sum(...n: Decimal.Value[]): Decimal;
static tan(n: Decimal.Value): Decimal;
static tanh(n: Decimal.Value): Decimal;
static trunc(n: Decimal.Value): Decimal;
static readonly default?: Decimal.Constructor;
static readonly Decimal?: Decimal.Constructor;
static readonly precision: number;
static readonly rounding: Decimal.Rounding;
static readonly toExpNeg: number;
static readonly toExpPos: number;
static readonly minE: number;
static readonly maxE: number;
static readonly crypto: boolean;
static readonly modulo: Decimal.Modulo;
static readonly ROUND_UP: 0;
static readonly ROUND_DOWN: 1;
static readonly ROUND_CEIL: 2;
static readonly ROUND_FLOOR: 3;
static readonly ROUND_HALF_UP: 4;
static readonly ROUND_HALF_DOWN: 5;
static readonly ROUND_HALF_EVEN: 6;
static readonly ROUND_HALF_CEIL: 7;
static readonly ROUND_HALF_FLOOR: 8;
static readonly EUCLID: 9;
}
declare type Exact<A, W> = (A extends unknown ? (W extends A ? {
[K in keyof A]: Exact<A[K], W[K]>;
} : W) : never) | (A extends Narrowable ? A : never);
export declare function getRuntime(): GetRuntimeOutput;
declare type GetRuntimeOutput = {
id: Runtime;
prettyName: string;
isEdge: boolean;
};
declare class JsonNull extends NullTypesEnumValue {
}
/**
* Generates more strict variant of an enum which, unlike regular enum,
* throws on non-existing property access. This can be useful in following situations:
* - we have an API, that accepts both `undefined` and `SomeEnumType` as an input
* - enum values are generated dynamically from DMMF.
*
* In that case, if using normal enums and no compile-time typechecking, using non-existing property
* will result in `undefined` value being used, which will be accepted. Using strict enum
* in this case will help to have a runtime exception, telling you that you are probably doing something wrong.
*
* Note: if you need to check for existence of a value in the enum you can still use either
* `in` operator or `hasOwnProperty` function.
*
* @param definition
* @returns
*/
export declare function makeStrictEnum<T extends Record<PropertyKey, string | number>>(definition: T): T;
declare type Narrowable = string | number | bigint | boolean | [];
declare class NullTypesEnumValue extends ObjectEnumValue {
_getNamespace(): string;
}
/**
* Base class for unique values of object-valued enums.
*/
declare abstract class ObjectEnumValue {
constructor(arg?: symbol);
abstract _getNamespace(): string;
_getName(): string;
toString(): string;
}
export declare const objectEnumValues: {
classes: {
DbNull: typeof DbNull;
JsonNull: typeof JsonNull;
AnyNull: typeof AnyNull;
};
instances: {
DbNull: DbNull;
JsonNull: JsonNull;
AnyNull: AnyNull;
};
};
declare type Operation = 'findFirst' | 'findFirstOrThrow' | 'findUnique' | 'findUniqueOrThrow' | 'findMany' | 'create' | 'createMany' | 'createManyAndReturn' | 'update' | 'updateMany' | 'upsert' | 'delete' | 'deleteMany' | 'aggregate' | 'count' | 'groupBy' | '$queryRaw' | '$executeRaw' | '$queryRawUnsafe' | '$executeRawUnsafe' | 'findRaw' | 'aggregateRaw' | '$runCommandRaw';
declare namespace Public {
export {
validator
}
}
export { Public }
declare type Runtime = "edge-routine" | "workerd" | "deno" | "lagon" | "react-native" | "netlify" | "electron" | "node" | "bun" | "edge-light" | "fastly" | "unknown";
declare function validator<V>(): <S>(select: Exact<S, V>) => S;
declare function validator<C, M extends Exclude<keyof C, `$${string}`>, O extends keyof C[M] & Operation>(client: C, model: M, operation: O): <S>(select: Exact<S, Args<C[M], O>>) => S;
declare function validator<C, M extends Exclude<keyof C, `$${string}`>, O extends keyof C[M] & Operation, P extends keyof Args<C[M], O>>(client: C, model: M, operation: O, prop: P): <S>(select: Exact<S, Args<C[M], O>[P]>) => S;
export { }

File diff suppressed because it is too large Load Diff

View File

@@ -129,6 +129,7 @@ model Note {
notebookId String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
contentUpdatedAt DateTime @default(now())
autoGenerated Boolean?
aiProvider String?
aiConfidence Int?

View File

@@ -210,6 +210,7 @@ exports.Prisma.NoteScalarFieldEnum = {
notebookId: 'notebookId',
createdAt: 'createdAt',
updatedAt: 'updatedAt',
contentUpdatedAt: 'contentUpdatedAt',
autoGenerated: 'autoGenerated',
aiProvider: 'aiProvider',
aiConfidence: 'aiConfidence',

Binary file not shown.

View File

@@ -129,6 +129,7 @@ model Note {
notebookId String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
contentUpdatedAt DateTime @default(now())
autoGenerated Boolean?
aiProvider String?
aiConfidence Int?

View File

@@ -0,0 +1,25 @@
import { prisma } from '../lib/prisma'
async function main() {
console.log('🔍 Checking users in database...')
console.log('Database URL used:', process.env.DATABASE_URL || "file:./dev.db")
const users = await prisma.user.findMany()
if (users.length === 0) {
console.log('❌ No users found in database!')
} else {
console.log(`✅ Found ${users.length} users:`)
console.table(users.map(u => ({
email: u.email,
role: u.role,
id: u.id,
hasPassword: !!u.password
})))
}
}
main()
.catch(e => console.error(e))
.finally(async () => await prisma.$disconnect())

View File

@@ -0,0 +1,41 @@
import { siteConfig } from '../config/site'
import { PrismaClient } from '@prisma/client'
async function main() {
console.log('🕵️‍♀️ Comparing Databases...')
// 1. Check Root DB
console.log('--- ROOT DB (./dev.db) ---')
const prismaRoot = new PrismaClient({
datasources: { db: { url: 'file:./dev.db' } }
})
try {
const countRoot = await prismaRoot.note.count()
console.log(`📦 Note Count: ${countRoot}`)
const usersRoot = await prismaRoot.user.count()
console.log(`👥 User Count: ${usersRoot}`)
} catch (e) {
console.log('❌ Failed to connect to Root DB', e)
} finally {
await prismaRoot.$disconnect()
}
// 2. Check Prisma Folder DB
console.log('\n--- PRISMA DB (./prisma/dev.db) ---')
const prismaPrisma = new PrismaClient({
datasources: { db: { url: 'file:./prisma/dev.db' } }
})
try {
const countPrisma = await prismaPrisma.note.count()
console.log(`📦 Note Count: ${countPrisma}`)
const usersPrisma = await prismaPrisma.user.count()
console.log(`👥 User Count: ${usersPrisma}`)
} catch (e) {
console.log('❌ Failed to connect to Prisma DB', e)
} finally {
await prismaPrisma.$disconnect()
}
}
main().catch(console.error)

View File

@@ -0,0 +1,36 @@
import { getAllNotes } from '../app/actions/notes'
import { prisma } from '../lib/prisma'
async function main() {
console.log('🕵️‍♀️ Debugging getAllNotes...')
// 1. Get raw DB data for a sample note
const rawNote = await prisma.note.findFirst({
where: { size: { not: 'small' } }
})
if (rawNote) {
console.log('📊 Raw DB Note (should be large/medium):', {
id: rawNote.id,
size: rawNote.size
})
} else {
console.log('⚠️ No notes with size != small found in DB directly.')
}
// 2. Mock auth/session if needed (actions check session)
// Since we can't easily mock next-auth in this script environment without setup,
// we might need to rely on the direct DB check above or check if getAllNotes extracts userId safely.
// getAllNotes checks `auth()`. In this script context, `auth()` will arguably return null.
// So we can't easily run `getAllNotes` directly if it guards auth.
// Let's modify the plan: We will check the DB directly to confirm PERMANENCE.
// Then we will manually simulate `parseNote` logic.
const notes = await prisma.note.findMany({ take: 5 })
console.log('📋 Checking first 5 notes sizes in DB:')
notes.forEach(n => console.log(`- ${n.id}: ${n.size}`))
}
main().catch(console.error).finally(() => prisma.$disconnect())

View File

@@ -0,0 +1,24 @@
import { prisma } from '../lib/prisma'
async function main() {
console.log('👑 Granting ADMIN access to ALL users...')
try {
const result = await prisma.user.updateMany({
data: {
role: 'ADMIN'
}
})
console.log(`✅ Success! Updated ${result.count} users to ADMIN role.`)
} catch (error) {
console.error('❌ Error updating users:', error)
process.exit(1)
}
}
main()
.catch(e => console.error(e))
.finally(async () => await prisma.$disconnect())

View File

@@ -0,0 +1,36 @@
import { prisma } from '../lib/prisma'
import bcrypt from 'bcryptjs'
async function main() {
const email = 'test@example.com'
const newPassword = 'password123'
console.log(`Resetting password for ${email}...`)
const hashedPassword = await bcrypt.hash(newPassword, 10)
try {
const user = await prisma.user.update({
where: { email },
data: {
password: hashedPassword,
resetToken: null,
resetTokenExpiry: null
},
})
console.log(`✅ Password successfully reset for ${user.email}`)
} catch (error) {
console.error('❌ Error resetting password:', error)
process.exit(1)
}
}
main()
.catch(e => {
console.error(e)
process.exit(1)
})
.finally(async () => {
await prisma.$disconnect()
})

View File

@@ -0,0 +1,63 @@
import { prisma } from '../lib/prisma'
// Copy of parseNote from app/actions/notes.ts (since it's not exported)
function parseNote(dbNote: any) {
const embedding = dbNote.embedding ? JSON.parse(dbNote.embedding) : null
if (embedding && Array.isArray(embedding)) {
// Simplified validation check for test
if (embedding.length !== 1536 && embedding.length !== 768 && embedding.length !== 384) {
return {
...dbNote,
checkItems: dbNote.checkItems ? JSON.parse(dbNote.checkItems) : null,
labels: dbNote.labels ? JSON.parse(dbNote.labels) : null,
images: dbNote.images ? JSON.parse(dbNote.images) : null,
links: dbNote.links ? JSON.parse(dbNote.links) : null,
embedding: null,
sharedWith: dbNote.sharedWith ? JSON.parse(dbNote.sharedWith) : [],
size: dbNote.size || 'small',
}
}
}
return {
...dbNote,
checkItems: dbNote.checkItems ? JSON.parse(dbNote.checkItems) : null,
labels: dbNote.labels ? JSON.parse(dbNote.labels) : null,
images: dbNote.images ? JSON.parse(dbNote.images) : null,
links: dbNote.links ? JSON.parse(dbNote.links) : null,
embedding,
sharedWith: dbNote.sharedWith ? JSON.parse(dbNote.sharedWith) : [],
size: dbNote.size || 'small',
}
}
async function main() {
console.log('🧪 Testing parseNote logic...')
// 1. Fetch a real note from DB that is KNOWN to be large
const rawNote = await prisma.note.findFirst({
where: { size: 'large' }
})
if (!rawNote) {
console.error('❌ No large note found in DB. Create one first.')
return
}
console.log('📊 Raw Note from DB:', { id: rawNote.id, size: rawNote.size })
// 2. Pass it through parseNote
const parsed = parseNote(rawNote)
console.log('🔄 Parsed Note:', { id: parsed.id, size: parsed.size })
if (parsed.size === 'large') {
console.log('✅ parseNote preserves size correctly.')
} else {
console.error('❌ parseNote returned wrong size:', parsed.size)
}
}
main().catch(console.error).finally(() => prisma.$disconnect())

View File

@@ -0,0 +1,56 @@
import { prisma } from '../lib/prisma'
import { updateSize } from '../app/actions/notes'
async function main() {
console.log('🧪 Starting Note Size Persistence Verification...')
// 1. Create a test note
const note = await prisma.note.create({
data: {
content: 'Size Test Note',
userId: (await prisma.user.findFirst())?.id || '',
size: 'small', // Start small
}
})
console.log(`📝 Created test note (${note.id}) with size: ${note.size}`)
if (!note.userId) {
console.error('❌ No user found to create note. Aborting.')
return
}
try {
// 2. Update size to LARGE
console.log('🔄 Updating size to LARGE...')
// We mock the session for the action or call prisma directly if action fails (actions usually need auth context)
// Since we're running as script, we'll use prisma update directly to simulate what the action does at DB level
// OR we can try to invoke the action if we can mock auth.
// Let's test the DB interaction first which is the critical "persistence" part.
await prisma.note.update({
where: { id: note.id },
data: { size: 'large' }
})
// 3. Fetch back
const updatedNote = await prisma.note.findUnique({ where: { id: note.id } })
console.log(`🔍 Fetched note after update. Size is: ${updatedNote?.size}`)
if (updatedNote?.size === 'large') {
console.log('✅ BACKEND PERSISTENCE: PASSED')
} else {
console.error('❌ BACKEND PERSISTENCE: FAILED (Size reverted or did not update)')
}
} catch (error) {
console.error('❌ Error during test:', error)
} finally {
// Cleanup
await prisma.note.delete({ where: { id: note.id } })
console.log('🧹 Cleaned up test note')
await prisma.$disconnect()
}
}
main().catch(console.error)

View File

@@ -2,61 +2,46 @@ import { test, expect } from '@playwright/test'
test.describe('Favorites Section', () => {
test.beforeEach(async ({ page }) => {
// Navigate to home page
await page.goto('/')
// Wait for page to load
await page.waitForLoadState('networkidle')
})
test('should not show favorites section when no notes are pinned', async ({ page }) => {
// Favorites section should not be present
const favoritesSection = page.locator('[data-testid="favorites-section"]')
await expect(favoritesSection).not.toBeVisible()
})
test('should pin a note and show it in favorites section', async ({ page }) => {
// Check if there are any existing notes
const existingNotes = page.locator('[data-testid="note-card"]')
const noteCount = await existingNotes.count()
if (noteCount === 0) {
// Skip test if no notes exist
test.skip()
test.skip(true, 'No notes exist to test pinning')
return
}
// Pin the first note
const firstNoteCard = existingNotes.first()
await firstNoteCard.hover()
// Find and click the pin button (it's near the top right)
const pinButton = firstNoteCard.locator('button').filter({ hasText: '' }).nth(0)
const pinButton = firstNoteCard.locator('[data-testid="pin-button"]')
await expect(pinButton).toBeVisible({ timeout: 5000 })
await pinButton.click()
// Wait for page refresh after pinning
await page.waitForTimeout(2000)
await expect(page.locator('[data-testid="favorites-section"]')).toBeVisible({ timeout: 10000 })
// Favorites section should be visible
const favoritesSection = page.locator('[data-testid="favorites-section"]')
await expect(favoritesSection).toBeVisible()
// Should have section title
const sectionTitle = favoritesSection.locator('h2')
const sectionTitle = page.locator('[data-testid="favorites-section"] h2')
await expect(sectionTitle).toContainText('Pinned')
// Should have at least 1 pinned note
const pinnedNotes = favoritesSection.locator('[data-testid="note-card"]')
await expect(pinnedNotes).toHaveCount(1)
const pinnedNotes = page.locator('[data-testid="favorites-section"] [data-testid="note-card"]')
await expect(pinnedNotes.first()).toBeVisible({ timeout: 5000 })
})
test('should unpin a note and remove it from favorites', async ({ page }) => {
// Check if there are any pinned notes already
const favoritesSection = page.locator('[data-testid="favorites-section"]')
const isFavoritesVisible = await favoritesSection.isVisible().catch(() => false)
if (!isFavoritesVisible) {
// Skip test if no favorites exist
test.skip()
test.skip(true, 'No favorites exist to test unpinning')
return
}
@@ -64,101 +49,78 @@ test.describe('Favorites Section', () => {
const pinnedCount = await pinnedNotes.count()
if (pinnedCount === 0) {
// Skip test if no pinned notes
test.skip()
test.skip(true, 'No pinned notes to unpin')
return
}
// Unpin the first pinned note
const firstPinnedNote = pinnedNotes.first()
await firstPinnedNote.hover()
const pinButton = firstPinnedNote.locator('button').filter({ hasText: '' }).nth(0)
const pinButton = firstPinnedNote.locator('[data-testid="pin-button"]')
await pinButton.click()
// Wait for page refresh after unpinning
await page.waitForTimeout(2000)
await page.waitForTimeout(500)
// After unpinning the last pinned note, section should be hidden
const updatedPinnedCount = await favoritesSection.locator('[data-testid="note-card"]').count().catch(() => 0)
const isStillVisible = await favoritesSection.isVisible().catch(() => false)
// If there were only 1 pinned note, section should be hidden
// Otherwise, count should be reduced
if (pinnedCount === 1) {
await expect(isStillVisible).toBe(false)
await expect(favoritesSection).not.toBeVisible({ timeout: 10000 })
} else {
await expect(updatedPinnedCount).toBe(pinnedCount - 1)
expect(updatedPinnedCount).toBe(pinnedCount - 1)
}
})
test('should show multiple pinned notes in favorites section', async ({ page }) => {
// Check if there are existing notes
const existingNotes = page.locator('[data-testid="note-card"]')
const noteCount = await existingNotes.count()
if (noteCount < 2) {
// Skip test if not enough notes exist
test.skip()
test.skip(true, 'Not enough notes to test multiple pins')
return
}
// Pin first two notes
for (let i = 0; i < 2; i++) {
const noteCard = existingNotes.nth(i)
await noteCard.hover()
const pinButton = noteCard.locator('button').filter({ hasText: '' }).nth(0)
const pinButton = noteCard.locator('[data-testid="pin-button"]')
await expect(pinButton).toBeVisible({ timeout: 5000 })
await pinButton.click()
// Wait for page refresh
await page.waitForTimeout(2000)
// Re-query notes after refresh
const refreshedNotes = page.locator('[data-testid="note-card"]')
await refreshedNotes.count()
await page.waitForTimeout(500)
}
// Favorites section should be visible
const favoritesSection = page.locator('[data-testid="favorites-section"]')
await expect(favoritesSection).toBeVisible()
await expect(favoritesSection).toBeVisible({ timeout: 10000 })
// Should have 2 pinned notes
const pinnedNotes = favoritesSection.locator('[data-testid="note-card"]')
await expect(pinnedNotes).toHaveCount(2)
const pinnedCount = await pinnedNotes.count()
expect(pinnedCount).toBeGreaterThanOrEqual(2)
})
test('should show favorites section above main notes', async ({ page }) => {
// Check if there are existing notes
const existingNotes = page.locator('[data-testid="note-card"]')
const noteCount = await existingNotes.count()
if (noteCount === 0) {
// Skip test if no notes exist
test.skip()
test.skip(true, 'No notes exist to test ordering')
return
}
// Pin a note
const firstNoteCard = existingNotes.first()
await firstNoteCard.hover()
const pinButton = firstNoteCard.locator('button').filter({ hasText: '' }).nth(0)
const pinButton = firstNoteCard.locator('[data-testid="pin-button"]')
await expect(pinButton).toBeVisible({ timeout: 5000 })
await pinButton.click()
// Wait for page refresh
await page.waitForTimeout(2000)
// Both sections should be visible
const favoritesSection = page.locator('[data-testid="favorites-section"]')
const mainNotesGrid = page.locator('[data-testid="notes-grid"]')
await expect(favoritesSection).toBeVisible()
await expect(favoritesSection).toBeVisible({ timeout: 10000 })
// Main notes grid might be visible only if there are unpinned notes
const hasUnpinnedNotes = await mainNotesGrid.isVisible().catch(() => false)
if (hasUnpinnedNotes) {
// Get Y positions to verify favorites is above
const favoritesY = await favoritesSection.boundingBox()
const mainNotesY = await mainNotesGrid.boundingBox()
@@ -167,4 +129,37 @@ test.describe('Favorites Section', () => {
}
}
})
test('should collapse and expand favorites section', async ({ page }) => {
const favoritesSection = page.locator('[data-testid="favorites-section"]')
const isFavoritesVisible = await favoritesSection.isVisible().catch(() => false)
if (!isFavoritesVisible) {
const existingNotes = page.locator('[data-testid="note-card"]')
const noteCount = await existingNotes.count()
if (noteCount === 0) {
test.skip(true, 'No notes to pin for collapse test')
return
}
const firstNoteCard = existingNotes.first()
await firstNoteCard.hover()
const pinButton = firstNoteCard.locator('[data-testid="pin-button"]')
await pinButton.click()
await expect(favoritesSection).toBeVisible({ timeout: 10000 })
}
const collapseButton = favoritesSection.locator('button').first()
const pinnedNoteCards = favoritesSection.locator('[data-testid="note-card"]')
await expect(pinnedNoteCards.first()).toBeVisible()
await collapseButton.click()
await expect(pinnedNoteCards.first()).not.toBeVisible()
await collapseButton.click()
await expect(pinnedNoteCards.first()).toBeVisible()
})
})