- Install better-sqlite3 for embedded SQLite support - Create complete database schema with photos, albums, tags, directories tables - Add PhotoService class with full CRUD operations and relationships - Create comprehensive API endpoints for photos, albums, directories, and stats - Add DirectoryList component with delete functionality and visual feedback - Implement directory saving to database when user selects path - Add automatic refresh of directory list when new directories are saved - Update Button component with enhanced enabled/disabled states and animations - Add Tab key handling to hide suggestions in directory modal - Update .gitignore to exclude SQLite database files 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
88 lines
2.7 KiB
TypeScript
88 lines
2.7 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server'
|
|
import { existsSync, statSync } from 'fs'
|
|
import { glob } from 'glob'
|
|
import path from 'path'
|
|
|
|
async function getSuggestions(inputPath: string): Promise<string[]> {
|
|
try {
|
|
const trimmedInput = inputPath.trim()
|
|
if (!trimmedInput) return []
|
|
|
|
// Create glob pattern based on input
|
|
const globPattern = `${trimmedInput}*`
|
|
|
|
console.log('Searching with pattern:', globPattern)
|
|
console.log('Input path exists:', existsSync(trimmedInput))
|
|
|
|
// Check if the base path exists first
|
|
if (trimmedInput.endsWith('/')) {
|
|
const basePath = trimmedInput.slice(0, -1)
|
|
console.log('Base path:', basePath, 'exists:', existsSync(basePath))
|
|
}
|
|
|
|
// Use glob to find matching directories
|
|
const matches = await glob(globPattern, {
|
|
withFileTypes: false, // Return strings not Dirent objects
|
|
absolute: true, // Return absolute paths
|
|
dot: true, // Include hidden directories
|
|
ignore: [], // Don't ignore any patterns
|
|
nodir: false // Include directories
|
|
})
|
|
|
|
console.log('Glob matches found:', matches.length, matches)
|
|
|
|
// Filter to only include directories
|
|
const directories = matches.filter(match => {
|
|
try {
|
|
const isDir = statSync(match).isDirectory()
|
|
if (isDir) console.log('Directory found:', match)
|
|
return isDir
|
|
} catch (error) {
|
|
console.log('Error checking:', match, error)
|
|
return false
|
|
}
|
|
})
|
|
|
|
console.log('Final directories:', directories)
|
|
return directories.slice(0, 10) // Limit to 10 suggestions
|
|
} catch (error) {
|
|
console.error('getSuggestions error:', error)
|
|
return []
|
|
}
|
|
}
|
|
|
|
export async function POST(request: NextRequest) {
|
|
try {
|
|
const { directory } = await request.json()
|
|
|
|
if (!directory || typeof directory !== 'string') {
|
|
return NextResponse.json({
|
|
valid: false,
|
|
error: 'Directory path is required',
|
|
suggestions: []
|
|
})
|
|
}
|
|
|
|
const trimmedInput = directory.trim()
|
|
|
|
// Always get suggestions using glob search
|
|
const suggestions = await getSuggestions(trimmedInput)
|
|
|
|
// Check if the input exactly matches an existing directory
|
|
const normalizedPath = path.resolve(trimmedInput)
|
|
const isValid = existsSync(normalizedPath) && statSync(normalizedPath).isDirectory()
|
|
|
|
return NextResponse.json({
|
|
valid: isValid,
|
|
path: isValid ? normalizedPath : undefined,
|
|
suggestions
|
|
})
|
|
|
|
} catch (error) {
|
|
return NextResponse.json({
|
|
valid: false,
|
|
error: 'Invalid directory path',
|
|
suggestions: []
|
|
}, { status: 400 })
|
|
}
|
|
} |