## Translation Files - Add 11 new language files (es, de, pt, ru, zh, ja, ko, ar, hi, nl, pl) - Add 100+ missing translation keys across all 15 languages - New sections: notebook, pagination, ai.batchOrganization, ai.autoLabels - Update nav section with workspace, quickAccess, myLibrary keys ## Component Updates - Update 15+ components to use translation keys instead of hardcoded text - Components: notebook dialogs, sidebar, header, note-input, ghost-tags, etc. - Replace 80+ hardcoded English/French strings with t() calls - Ensure consistent UI across all supported languages ## Code Quality - Remove 77+ console.log statements from codebase - Clean up API routes, components, hooks, and services - Keep only essential error handling (no debugging logs) ## UI/UX Improvements - Update Keep logo to yellow post-it style (from-yellow-400 to-amber-500) - Change selection colors to #FEF3C6 (notebooks) and #EFB162 (nav items) - Make "+" button permanently visible in notebooks section - Fix grammar and syntax errors in multiple components ## Bug Fixes - Fix JSON syntax errors in it.json, nl.json, pl.json, zh.json - Fix syntax errors in notebook-suggestion-toast.tsx - Fix syntax errors in use-auto-tagging.ts - Fix syntax errors in paragraph-refactor.service.ts - Fix duplicate "fusion" section in nl.json 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> Ou une version plus courte si vous préférez : feat(i18n): Add 15 languages, remove logs, update UI components - Create 11 new translation files (es, de, pt, ru, zh, ja, ko, ar, hi, nl, pl) - Add 100+ translation keys: notebook, pagination, AI features - Update 15+ components to use translations (80+ strings) - Remove 77+ console.log statements from codebase - Fix JSON syntax errors in 4 translation files - Fix component syntax errors (toast, hooks, services) - Update logo to yellow post-it style - Change selection colors (#FEF3C6, #EFB162) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
168 lines
4.7 KiB
TypeScript
168 lines
4.7 KiB
TypeScript
/**
|
||
* Rollback Script: Notebooks → Tags
|
||
*
|
||
* This script rolls back the notebooks migration by:
|
||
* 1. Deleting all notebooks
|
||
* 2. Removing notebookId from labels (set to empty string)
|
||
* 3. Removing notebookId from notes (set to null)
|
||
*
|
||
* WARNING: This will revert ALL notebook-related changes!
|
||
* Make sure you have a database backup before running this.
|
||
*
|
||
* Usage:
|
||
* npx tsx scripts/rollback-notebooks.ts
|
||
*
|
||
* Confirm by adding --confirm flag:
|
||
* npx tsx scripts/rollback-notebooks.ts --confirm
|
||
*/
|
||
|
||
import { prisma } from '../keep-notes/lib/prisma'
|
||
|
||
interface RollbackStats {
|
||
notebooksDeleted: number
|
||
labelsUpdated: number
|
||
notesUpdated: number
|
||
errors: string[]
|
||
}
|
||
|
||
/**
|
||
* Main rollback function
|
||
*/
|
||
async function rollbackNotebooks(confirm = false): Promise<RollbackStats> {
|
||
console.log('⚠️ NOTEBOOKS ROLLBACK\n')
|
||
|
||
if (!confirm) {
|
||
console.log('❌ ERROR: Rollback requires confirmation.')
|
||
console.log('\nTo rollback, run with --confirm flag:')
|
||
console.log(' npx tsx scripts/rollback-notebooks.ts --confirm')
|
||
console.log('\n⚠️ This will:')
|
||
console.log(' - Delete ALL notebooks')
|
||
console.log(' - Remove notebookId from all labels')
|
||
console.log(' - Remove notebookId from all notes')
|
||
console.log(' - IRREVERSIBLY delete notebook associations\n')
|
||
process.exit(1)
|
||
}
|
||
|
||
console.log('🔄 Starting rollback...\n')
|
||
|
||
const stats: RollbackStats = {
|
||
notebooksDeleted: 0,
|
||
labelsUpdated: 0,
|
||
notesUpdated: 0,
|
||
errors: [],
|
||
}
|
||
|
||
try {
|
||
// Step 1: Get count before rollback
|
||
console.log('📊 Counting items to rollback...')
|
||
|
||
const notebookCount = await prisma.notebook.count()
|
||
const labelCount = await prisma.label.count({
|
||
where: {
|
||
notebookId: {
|
||
not: '',
|
||
},
|
||
},
|
||
})
|
||
const noteCount = await prisma.note.count({
|
||
where: {
|
||
notebookId: {
|
||
not: null,
|
||
},
|
||
},
|
||
})
|
||
|
||
console.log(` Notebooks to delete: ${notebookCount}`)
|
||
console.log(` Labels to update: ${labelCount}`)
|
||
console.log(` Notes to update: ${noteCount}\n`)
|
||
|
||
if (notebookCount === 0 && labelCount === 0 && noteCount === 0) {
|
||
console.log('ℹ️ Nothing to rollback. System is already in pre-migration state.\n')
|
||
return stats
|
||
}
|
||
|
||
// Step 2: Update labels (remove notebookId)
|
||
if (labelCount > 0) {
|
||
console.log('🏷️ Updating labels...')
|
||
const labelResult = await prisma.label.updateMany({
|
||
where: {
|
||
notebookId: {
|
||
not: '',
|
||
},
|
||
},
|
||
data: {
|
||
notebookId: '',
|
||
},
|
||
})
|
||
stats.labelsUpdated = labelResult.count
|
||
console.log(` ✅ Updated ${stats.labelsUpdated} label(s)`)
|
||
}
|
||
|
||
// Step 3: Update notes (remove notebookId)
|
||
if (noteCount > 0) {
|
||
console.log('📝 Updating notes...')
|
||
const noteResult = await prisma.note.updateMany({
|
||
where: {
|
||
notebookId: {
|
||
not: null,
|
||
},
|
||
},
|
||
data: {
|
||
notebookId: null,
|
||
},
|
||
})
|
||
stats.notesUpdated = noteResult.count
|
||
console.log(` ✅ Updated ${stats.notesUpdated} note(s)`)
|
||
}
|
||
|
||
// Step 4: Delete notebooks (cascade deletes labels, but notes are already updated)
|
||
if (notebookCount > 0) {
|
||
console.log('📁 Deleting notebooks...')
|
||
const notebookResult = await prisma.notebook.deleteMany({})
|
||
stats.notebooksDeleted = notebookResult.count
|
||
console.log(` ✅ Deleted ${stats.notebooksDeleted} notebook(s)`)
|
||
}
|
||
|
||
// Summary
|
||
console.log('\n' + '='.repeat(60))
|
||
console.log('✅ Rollback complete!\n')
|
||
console.log('📊 Summary:')
|
||
console.log(` Notebooks deleted: ${stats.notebooksDeleted}`)
|
||
console.log(` Labels updated: ${stats.labelsUpdated}`)
|
||
console.log(` Notes updated: ${stats.notesUpdated}`)
|
||
|
||
if (stats.errors.length > 0) {
|
||
console.log(`\n⚠️ Errors: ${stats.errors.length}`)
|
||
stats.errors.forEach((error) => console.log(` ❌ ${error}`))
|
||
}
|
||
|
||
console.log('\n' + '='.repeat(60))
|
||
console.log('\n✨ Rollback successful!')
|
||
console.log('\n📌 System is now back to the flat tags model:')
|
||
console.log(' - All notebooks removed')
|
||
console.log(' - All labels detached from notebooks')
|
||
console.log(' - All notes back in "Notes générales" (Inbox)\n')
|
||
|
||
return stats
|
||
} catch (error) {
|
||
console.error('\n❌ Rollback failed:', error)
|
||
throw error
|
||
} finally {
|
||
await prisma.$disconnect()
|
||
}
|
||
}
|
||
|
||
// Run rollback
|
||
const args = process.argv.slice(2)
|
||
const isConfirmed = args.includes('--confirm')
|
||
|
||
rollbackNotebooks(isConfirmed)
|
||
.then(() => {
|
||
console.log('✨ All done!')
|
||
process.exit(0)
|
||
})
|
||
.catch((error) => {
|
||
console.error('\n💥 Fatal error:', error)
|
||
process.exit(1)
|
||
})
|