feat: add reminders page, BMad skills upgrade, MCP server refactor

- Add reminders page with navigation support
- Upgrade BMad builder module to skills-based architecture
- Refactor MCP server: extract tools and auth into separate modules
- Add connections cache, custom AI provider support
- Update prisma schema and generated client
- Various UI/UX improvements and i18n updates
- Add service worker for PWA support

Made-with: Cursor
This commit is contained in:
Sepehr Ramezani
2026-04-13 21:02:53 +02:00
parent 18ed116e0d
commit fa7e166f3e
3099 changed files with 397228 additions and 14584 deletions

View File

@@ -85,7 +85,9 @@ export function NoteEditor({ note, readOnly = false, onClose }: NoteEditorProps)
// Reminder state
const [showReminderDialog, setShowReminderDialog] = useState(false)
const [currentReminder, setCurrentReminder] = useState<Date | null>(note.reminder)
const [currentReminder, setCurrentReminder] = useState<Date | null>(
note.reminder ? new Date(note.reminder as unknown as string) : null
)
// Link state
const [showLinkDialog, setShowLinkDialog] = useState(false)
@@ -325,12 +327,12 @@ export function NoteEditor({ note, readOnly = false, onClose }: NoteEditorProps)
body: JSON.stringify({ text: content, option: 'clarify' })
})
const data = await response.json()
if (!response.ok) throw new Error(data.error || 'Failed to clarify')
if (!response.ok) throw new Error(data.error || t('notes.clarifyFailed'))
setContent(data.reformulatedText || data.text)
toast.success(t('ai.reformulationApplied'))
} catch (error) {
console.error('Clarify error:', error)
toast.error(t('ai.reformulationFailed'))
toast.error(t('notes.clarifyFailed'))
} finally {
setIsProcessingAI(false)
}
@@ -351,12 +353,12 @@ export function NoteEditor({ note, readOnly = false, onClose }: NoteEditorProps)
body: JSON.stringify({ text: content, option: 'shorten' })
})
const data = await response.json()
if (!response.ok) throw new Error(data.error || 'Failed to shorten')
if (!response.ok) throw new Error(data.error || t('notes.shortenFailed'))
setContent(data.reformulatedText || data.text)
toast.success(t('ai.reformulationApplied'))
} catch (error) {
console.error('Shorten error:', error)
toast.error(t('ai.reformulationFailed'))
toast.error(t('notes.shortenFailed'))
} finally {
setIsProcessingAI(false)
}
@@ -377,12 +379,12 @@ export function NoteEditor({ note, readOnly = false, onClose }: NoteEditorProps)
body: JSON.stringify({ text: content, option: 'improve' })
})
const data = await response.json()
if (!response.ok) throw new Error(data.error || 'Failed to improve')
if (!response.ok) throw new Error(data.error || t('notes.improveFailed'))
setContent(data.reformulatedText || data.text)
toast.success(t('ai.reformulationApplied'))
} catch (error) {
console.error('Improve error:', error)
toast.error(t('ai.reformulationFailed'))
toast.error(t('notes.improveFailed'))
} finally {
setIsProcessingAI(false)
}
@@ -408,7 +410,7 @@ export function NoteEditor({ note, readOnly = false, onClose }: NoteEditorProps)
body: JSON.stringify({ text: content })
})
const data = await response.json()
if (!response.ok) throw new Error(data.error || 'Failed to transform')
if (!response.ok) throw new Error(data.error || t('notes.transformFailed'))
// Set the transformed markdown content and enable markdown mode
setContent(data.transformedText)
@@ -440,18 +442,28 @@ export function NoteEditor({ note, readOnly = false, onClose }: NoteEditorProps)
toast.success(t('ai.reformulationApplied'))
}
const handleReminderSave = (date: Date) => {
const handleReminderSave = async (date: Date) => {
if (date < new Date()) {
toast.error(t('notes.reminderPastError'))
return
}
setCurrentReminder(date)
toast.success(t('notes.reminderSet', { date: date.toLocaleString() }))
try {
await updateNote(note.id, { reminder: date })
toast.success(t('notes.reminderSet', { datetime: date.toLocaleString() }))
} catch {
toast.error(t('notebook.savingReminder'))
}
}
const handleRemoveReminder = () => {
const handleRemoveReminder = async () => {
setCurrentReminder(null)
toast.success(t('notes.reminderRemoved'))
try {
await updateNote(note.id, { reminder: null })
toast.success(t('notes.reminderRemoved'))
} catch {
toast.error(t('notebook.removingReminder'))
}
}
const handleSave = async () => {