mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-21 14:21:46 +00:00
feat: undo button for trip planner
Implements a full undo history system for the Plan screen. New hook: usePlannerHistory (client/src/hooks/usePlannerHistory.ts) - Maintains a LIFO stack (up to 30 entries) of reversible actions - Exposes pushUndo(label, fn), undo(), canUndo, lastActionLabel Tracked actions: - Assign place to day (undo: remove the assignment) - Remove place from day (undo: re-assign at original position) - Reorder places within a day (undo: restore previous order) - Move place to a different day (undo: move back) - Optimize route (undo: restore original order) - Lock / unlock place (undo: toggle back) - Delete place (undo: recreate place + restore all day assignments) - Add place (undo: delete it) - Import from GPX (undo: delete all imported places) - Import from Google Maps list (undo: delete all imported places) UI: Undo button (Undo2 icon) in DayPlanSidebar header. PDF, ICS and Undo buttons all use custom instant hover tooltips instead of native title attributes. A toast notification confirms each undo action. Translations: undo.* keys added to all 12 language files.
This commit is contained in:
@@ -1488,6 +1488,19 @@ const ar: Record<string, string | { name: string; category: string }[]> = {
|
||||
'perm.actionHint.packing_edit': 'من يمكنه إدارة عناصر التعبئة والحقائب',
|
||||
'perm.actionHint.collab_edit': 'من يمكنه إنشاء ملاحظات واستطلاعات وإرسال رسائل',
|
||||
'perm.actionHint.share_manage': 'من يمكنه إنشاء أو حذف روابط المشاركة العامة',
|
||||
// Undo
|
||||
'undo.button': 'Undo',
|
||||
'undo.tooltip': 'Undo: {action}',
|
||||
'undo.assignPlace': 'Place assigned to day',
|
||||
'undo.removeAssignment': 'Place removed from day',
|
||||
'undo.reorder': 'Places reordered',
|
||||
'undo.optimize': 'Route optimized',
|
||||
'undo.deletePlace': 'Place deleted',
|
||||
'undo.moveDay': 'Place moved to another day',
|
||||
'undo.lock': 'Place lock toggled',
|
||||
'undo.importGpx': 'GPX import',
|
||||
'undo.importGoogleList': 'Google Maps import',
|
||||
|
||||
}
|
||||
|
||||
export default ar
|
||||
|
||||
@@ -1483,6 +1483,19 @@ const br: Record<string, string | { name: string; category: string }[]> = {
|
||||
'perm.actionHint.packing_edit': 'Quem pode gerenciar itens de bagagem e malas',
|
||||
'perm.actionHint.collab_edit': 'Quem pode criar notas, enquetes e enviar mensagens',
|
||||
'perm.actionHint.share_manage': 'Quem pode criar ou excluir links de compartilhamento públicos',
|
||||
// Undo
|
||||
'undo.button': 'Undo',
|
||||
'undo.tooltip': 'Undo: {action}',
|
||||
'undo.assignPlace': 'Place assigned to day',
|
||||
'undo.removeAssignment': 'Place removed from day',
|
||||
'undo.reorder': 'Places reordered',
|
||||
'undo.optimize': 'Route optimized',
|
||||
'undo.deletePlace': 'Place deleted',
|
||||
'undo.moveDay': 'Place moved to another day',
|
||||
'undo.lock': 'Place lock toggled',
|
||||
'undo.importGpx': 'GPX import',
|
||||
'undo.importGoogleList': 'Google Maps import',
|
||||
|
||||
}
|
||||
|
||||
export default br
|
||||
|
||||
@@ -507,8 +507,6 @@ const cs: Record<string, string | { name: string; category: string }[]> = {
|
||||
'admin.addons.toast.updated': 'Doplněk byl aktualizován',
|
||||
'admin.addons.toast.error': 'Aktualizace doplňku se nezdařila',
|
||||
'admin.addons.noAddons': 'Žádné doplňky nejsou k dispozici',
|
||||
'admin.addons.catalog.memories.name': 'Fotky (Immich)',
|
||||
'admin.addons.catalog.memories.description': 'Sdílejte cestovní fotky přes vaši instanci Immich',
|
||||
'admin.addons.catalog.mcp.name': 'MCP',
|
||||
'admin.addons.catalog.mcp.description': 'Model Context Protocol pro integraci AI asistentů',
|
||||
'admin.addons.subtitleBefore': 'Zapněte nebo vypněte funkce a přizpůsobte si ',
|
||||
@@ -1488,6 +1486,19 @@ const cs: Record<string, string | { name: string; category: string }[]> = {
|
||||
'perm.actionHint.packing_edit': 'Kdo může spravovat položky balení a tašky',
|
||||
'perm.actionHint.collab_edit': 'Kdo může vytvářet poznámky, hlasování a posílat zprávy',
|
||||
'perm.actionHint.share_manage': 'Kdo může vytvářet nebo mazat veřejné odkazy ke sdílení',
|
||||
// Undo
|
||||
'undo.button': 'Undo',
|
||||
'undo.tooltip': 'Undo: {action}',
|
||||
'undo.assignPlace': 'Place assigned to day',
|
||||
'undo.removeAssignment': 'Place removed from day',
|
||||
'undo.reorder': 'Places reordered',
|
||||
'undo.optimize': 'Route optimized',
|
||||
'undo.deletePlace': 'Place deleted',
|
||||
'undo.moveDay': 'Place moved to another day',
|
||||
'undo.lock': 'Place lock toggled',
|
||||
'undo.importGpx': 'GPX import',
|
||||
'undo.importGoogleList': 'Google Maps import',
|
||||
|
||||
}
|
||||
|
||||
export default cs
|
||||
|
||||
@@ -1485,6 +1485,19 @@ const de: Record<string, string | { name: string; category: string }[]> = {
|
||||
'perm.actionHint.packing_edit': 'Wer kann Packstücke und Taschen verwalten',
|
||||
'perm.actionHint.collab_edit': 'Wer kann Notizen, Umfragen erstellen und Nachrichten senden',
|
||||
'perm.actionHint.share_manage': 'Wer kann öffentliche Freigabelinks erstellen oder löschen',
|
||||
// Undo
|
||||
'undo.button': 'Undo',
|
||||
'undo.tooltip': 'Undo: {action}',
|
||||
'undo.assignPlace': 'Place assigned to day',
|
||||
'undo.removeAssignment': 'Place removed from day',
|
||||
'undo.reorder': 'Places reordered',
|
||||
'undo.optimize': 'Route optimized',
|
||||
'undo.deletePlace': 'Place deleted',
|
||||
'undo.moveDay': 'Place moved to another day',
|
||||
'undo.lock': 'Place lock toggled',
|
||||
'undo.importGpx': 'GPX import',
|
||||
'undo.importGoogleList': 'Google Maps import',
|
||||
|
||||
}
|
||||
|
||||
export default de
|
||||
|
||||
@@ -1482,6 +1482,21 @@ const en: Record<string, string | { name: string; category: string }[]> = {
|
||||
'perm.actionHint.packing_edit': 'Who can manage packing items and bags',
|
||||
'perm.actionHint.collab_edit': 'Who can create notes, polls and send messages',
|
||||
'perm.actionHint.share_manage': 'Who can create or delete public share links',
|
||||
|
||||
// Undo
|
||||
'undo.button': 'Undo',
|
||||
'undo.tooltip': 'Undo: {action}',
|
||||
'undo.assignPlace': 'Place assigned to day',
|
||||
'undo.removeAssignment': 'Place removed from day',
|
||||
'undo.reorder': 'Places reordered',
|
||||
'undo.optimize': 'Route optimized',
|
||||
'undo.deletePlace': 'Place deleted',
|
||||
'undo.moveDay': 'Place moved to another day',
|
||||
'undo.lock': 'Place lock toggled',
|
||||
'undo.importGpx': 'GPX import',
|
||||
'undo.importGoogleList': 'Google Maps import',
|
||||
'undo.addPlace': 'Place added',
|
||||
'undo.done': 'Undone: {action}',
|
||||
}
|
||||
|
||||
export default en
|
||||
|
||||
@@ -1490,6 +1490,19 @@ const es: Record<string, string> = {
|
||||
'perm.actionHint.packing_edit': 'Quién puede gestionar artículos de equipaje y bolsas',
|
||||
'perm.actionHint.collab_edit': 'Quién puede crear notas, encuestas y enviar mensajes',
|
||||
'perm.actionHint.share_manage': 'Quién puede crear o eliminar enlaces compartidos públicos',
|
||||
// Undo
|
||||
'undo.button': 'Undo',
|
||||
'undo.tooltip': 'Undo: {action}',
|
||||
'undo.assignPlace': 'Place assigned to day',
|
||||
'undo.removeAssignment': 'Place removed from day',
|
||||
'undo.reorder': 'Places reordered',
|
||||
'undo.optimize': 'Route optimized',
|
||||
'undo.deletePlace': 'Place deleted',
|
||||
'undo.moveDay': 'Place moved to another day',
|
||||
'undo.lock': 'Place lock toggled',
|
||||
'undo.importGpx': 'GPX import',
|
||||
'undo.importGoogleList': 'Google Maps import',
|
||||
|
||||
}
|
||||
|
||||
export default es
|
||||
|
||||
@@ -1484,6 +1484,19 @@ const fr: Record<string, string> = {
|
||||
'perm.actionHint.packing_edit': 'Qui peut gérer les articles de bagages et les sacs',
|
||||
'perm.actionHint.collab_edit': 'Qui peut créer des notes, des sondages et envoyer des messages',
|
||||
'perm.actionHint.share_manage': 'Qui peut créer ou supprimer des liens de partage publics',
|
||||
// Undo
|
||||
'undo.button': 'Undo',
|
||||
'undo.tooltip': 'Undo: {action}',
|
||||
'undo.assignPlace': 'Place assigned to day',
|
||||
'undo.removeAssignment': 'Place removed from day',
|
||||
'undo.reorder': 'Places reordered',
|
||||
'undo.optimize': 'Route optimized',
|
||||
'undo.deletePlace': 'Place deleted',
|
||||
'undo.moveDay': 'Place moved to another day',
|
||||
'undo.lock': 'Place lock toggled',
|
||||
'undo.importGpx': 'GPX import',
|
||||
'undo.importGoogleList': 'Google Maps import',
|
||||
|
||||
}
|
||||
|
||||
export default fr
|
||||
|
||||
@@ -1485,6 +1485,19 @@ const hu: Record<string, string | { name: string; category: string }[]> = {
|
||||
'perm.actionHint.packing_edit': 'Ki kezelheti a csomagolási tételeket és táskákat',
|
||||
'perm.actionHint.collab_edit': 'Ki hozhat létre jegyzeteket, szavazásokat és küldhet üzeneteket',
|
||||
'perm.actionHint.share_manage': 'Ki hozhat létre vagy törölhet nyilvános megosztási linkeket',
|
||||
// Undo
|
||||
'undo.button': 'Undo',
|
||||
'undo.tooltip': 'Undo: {action}',
|
||||
'undo.assignPlace': 'Place assigned to day',
|
||||
'undo.removeAssignment': 'Place removed from day',
|
||||
'undo.reorder': 'Places reordered',
|
||||
'undo.optimize': 'Route optimized',
|
||||
'undo.deletePlace': 'Place deleted',
|
||||
'undo.moveDay': 'Place moved to another day',
|
||||
'undo.lock': 'Place lock toggled',
|
||||
'undo.importGpx': 'GPX import',
|
||||
'undo.importGoogleList': 'Google Maps import',
|
||||
|
||||
}
|
||||
|
||||
export default hu
|
||||
|
||||
@@ -1485,6 +1485,21 @@ const it: Record<string, string | { name: string; category: string }[]> = {
|
||||
'perm.actionHint.packing_edit': 'Chi può gestire articoli da bagaglio e borse',
|
||||
'perm.actionHint.collab_edit': 'Chi può creare note, sondaggi e inviare messaggi',
|
||||
'perm.actionHint.share_manage': 'Chi può creare o eliminare link di condivisione pubblici',
|
||||
|
||||
// Undo
|
||||
'undo.button': 'Annulla',
|
||||
'undo.tooltip': 'Annulla: {action}',
|
||||
'undo.assignPlace': 'Luogo assegnato al giorno',
|
||||
'undo.removeAssignment': 'Luogo rimosso dal giorno',
|
||||
'undo.reorder': 'Luoghi riordinati',
|
||||
'undo.optimize': 'Percorso ottimizzato',
|
||||
'undo.deletePlace': 'Luogo eliminato',
|
||||
'undo.moveDay': 'Luogo spostato in altro giorno',
|
||||
'undo.lock': 'Blocco luogo modificato',
|
||||
'undo.importGpx': 'Importazione GPX',
|
||||
'undo.importGoogleList': 'Importazione Google Maps',
|
||||
'undo.addPlace': 'Luogo aggiunto',
|
||||
'undo.done': 'Annullato: {action}',
|
||||
}
|
||||
|
||||
export default it
|
||||
|
||||
@@ -1484,6 +1484,19 @@ const nl: Record<string, string> = {
|
||||
'perm.actionHint.packing_edit': 'Wie kan pakitems en tassen beheren',
|
||||
'perm.actionHint.collab_edit': 'Wie kan notities, polls aanmaken en berichten versturen',
|
||||
'perm.actionHint.share_manage': 'Wie kan openbare deellinks aanmaken of verwijderen',
|
||||
// Undo
|
||||
'undo.button': 'Undo',
|
||||
'undo.tooltip': 'Undo: {action}',
|
||||
'undo.assignPlace': 'Place assigned to day',
|
||||
'undo.removeAssignment': 'Place removed from day',
|
||||
'undo.reorder': 'Places reordered',
|
||||
'undo.optimize': 'Route optimized',
|
||||
'undo.deletePlace': 'Place deleted',
|
||||
'undo.moveDay': 'Place moved to another day',
|
||||
'undo.lock': 'Place lock toggled',
|
||||
'undo.importGpx': 'GPX import',
|
||||
'undo.importGoogleList': 'Google Maps import',
|
||||
|
||||
}
|
||||
|
||||
export default nl
|
||||
|
||||
@@ -1484,6 +1484,19 @@ const ru: Record<string, string> = {
|
||||
'perm.actionHint.packing_edit': 'Кто может управлять вещами для сборов и сумками',
|
||||
'perm.actionHint.collab_edit': 'Кто может создавать заметки, опросы и отправлять сообщения',
|
||||
'perm.actionHint.share_manage': 'Кто может создавать или удалять публичные ссылки для обмена',
|
||||
// Undo
|
||||
'undo.button': 'Undo',
|
||||
'undo.tooltip': 'Undo: {action}',
|
||||
'undo.assignPlace': 'Place assigned to day',
|
||||
'undo.removeAssignment': 'Place removed from day',
|
||||
'undo.reorder': 'Places reordered',
|
||||
'undo.optimize': 'Route optimized',
|
||||
'undo.deletePlace': 'Place deleted',
|
||||
'undo.moveDay': 'Place moved to another day',
|
||||
'undo.lock': 'Place lock toggled',
|
||||
'undo.importGpx': 'GPX import',
|
||||
'undo.importGoogleList': 'Google Maps import',
|
||||
|
||||
}
|
||||
|
||||
export default ru
|
||||
|
||||
@@ -1484,6 +1484,19 @@ const zh: Record<string, string> = {
|
||||
'perm.actionHint.packing_edit': '谁可以管理行李物品和包袋',
|
||||
'perm.actionHint.collab_edit': '谁可以创建笔记、投票和发送消息',
|
||||
'perm.actionHint.share_manage': '谁可以创建或删除公开分享链接',
|
||||
// Undo
|
||||
'undo.button': 'Undo',
|
||||
'undo.tooltip': 'Undo: {action}',
|
||||
'undo.assignPlace': 'Place assigned to day',
|
||||
'undo.removeAssignment': 'Place removed from day',
|
||||
'undo.reorder': 'Places reordered',
|
||||
'undo.optimize': 'Route optimized',
|
||||
'undo.deletePlace': 'Place deleted',
|
||||
'undo.moveDay': 'Place moved to another day',
|
||||
'undo.lock': 'Place lock toggled',
|
||||
'undo.importGpx': 'GPX import',
|
||||
'undo.importGoogleList': 'Google Maps import',
|
||||
|
||||
}
|
||||
|
||||
export default zh
|
||||
|
||||
Reference in New Issue
Block a user