Skip to content

Commit 95a9ca0

Browse files
committed
feat: add description editing and reset templates functionality
- Add description input field to template editor header - Add resetPrintTemplatesToDefaults function that deletes all templates and recreates from default_print_templates table - Change "Restore Default" to "Reset to Defaults" button with confirmation dialog - Simplify UI by removing per-template restore dropdown
1 parent a81eb17 commit 95a9ca0

File tree

4 files changed

+94
-100
lines changed

4 files changed

+94
-100
lines changed

src/main/api.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ import {
5959
setDefaultPrintTemplate,
6060
listDefaultPrintTemplates,
6161
getDefaultPrintTemplateByKey,
62-
restorePrintTemplateFromDefault
62+
restorePrintTemplateFromDefault,
63+
resetPrintTemplatesToDefaults
6364
} from './repository/print-template'
6465

6566
// Custom APIs for renderer
@@ -124,7 +125,8 @@ export const api = {
124125
setDefaultPrintTemplate,
125126
listDefaultPrintTemplates,
126127
getDefaultPrintTemplateByKey,
127-
restorePrintTemplateFromDefault
128+
restorePrintTemplateFromDefault,
129+
resetPrintTemplatesToDefaults
128130
}
129131

130132
export type ApiType = typeof api

src/main/repository/print-template.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,3 +281,36 @@ export const restorePrintTemplateFromDefault = async (
281281
isDefault: options.setAsDefault ?? false
282282
})
283283
}
284+
285+
// Reset all print templates to defaults
286+
// Deletes ALL existing templates and recreates from default templates
287+
export const resetPrintTemplatesToDefaults = async (): Promise<PrintTemplate[]> => {
288+
// Delete all existing print templates
289+
await db.deleteFrom('print_templates').execute()
290+
291+
// Get all default templates
292+
const defaults = await listDefaultPrintTemplates()
293+
294+
// Track which types we've seen to set first of each type as default
295+
const seenTypes = new Set<TemplateType>()
296+
297+
// Create templates from each default
298+
const created: PrintTemplate[] = []
299+
for (const defaultTemplate of defaults) {
300+
const isFirstOfType = !seenTypes.has(defaultTemplate.type)
301+
seenTypes.add(defaultTemplate.type)
302+
303+
const template = await createPrintTemplate({
304+
name: defaultTemplate.name,
305+
type: defaultTemplate.type,
306+
description: defaultTemplate.description,
307+
structure: defaultTemplate.structure,
308+
pageSettings: defaultTemplate.pageSettings,
309+
isDefault: isFirstOfType
310+
})
311+
312+
created.push(template)
313+
}
314+
315+
return created
316+
}

src/renderer/src/components/settings/PrintTemplatesSettings.tsx

Lines changed: 37 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,7 @@ import {
1616
import { cn } from '../../lib/utils'
1717
import { queries } from '../../lib/queries'
1818
import { unwrapResult } from '../../lib/utils'
19-
import {
20-
PrintTemplate,
21-
DefaultPrintTemplate,
22-
TemplateType
23-
} from '../../../../shared/types/template-blocks'
19+
import { PrintTemplate, TemplateType } from '../../../../shared/types/template-blocks'
2420
import { Button } from '../../components/ui/button'
2521
import { Card, CardDescription, CardHeader, CardTitle } from '../../components/ui/card'
2622
import {
@@ -40,30 +36,17 @@ import {
4036
AlertDialogHeader,
4137
AlertDialogTitle
4238
} from '../../components/ui/alert-dialog'
43-
import {
44-
Dialog,
45-
DialogContent,
46-
DialogDescription,
47-
DialogFooter,
48-
DialogHeader,
49-
DialogTitle
50-
} from '../../components/ui/dialog'
5139
import { toast } from 'sonner'
5240
import { Badge } from '../../components/ui/badge'
53-
import { Checkbox } from '../../components/ui/checkbox'
54-
import { Label } from '../../components/ui/label'
5541

5642
export const PrintTemplatesSettings = () => {
5743
const navigate = useNavigate()
5844
const queryClient = useQueryClient()
5945
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false)
6046
const [templateToDelete, setTemplateToDelete] = useState<PrintTemplate | null>(null)
61-
const [restoreDialogOpen, setRestoreDialogOpen] = useState(false)
62-
const [selectedDefault, setSelectedDefault] = useState<DefaultPrintTemplate | null>(null)
63-
const [setAsDefault, setSetAsDefault] = useState(false)
47+
const [resetDialogOpen, setResetDialogOpen] = useState(false)
6448

6549
const { data: templatesData, isLoading } = useQuery(queries.printTemplates.list({}))
66-
const { data: defaultTemplates } = useQuery(queries.printTemplates.defaults())
6750

6851
const deleteMutation = useMutation({
6952
mutationFn: (id: number) => unwrapResult(window.api.invoke('deletePrintTemplateById', id)),
@@ -105,21 +88,15 @@ export const PrintTemplatesSettings = () => {
10588
}
10689
})
10790

108-
const restoreMutation = useMutation({
109-
mutationFn: ({ key, setAsDefault }: { key: string; setAsDefault: boolean }) =>
110-
unwrapResult(window.api.invoke('restorePrintTemplateFromDefault', key, { setAsDefault })),
111-
onSuccess: (result) => {
91+
const resetMutation = useMutation({
92+
mutationFn: () => unwrapResult(window.api.invoke('resetPrintTemplatesToDefaults')),
93+
onSuccess: () => {
11294
queryClient.invalidateQueries({ queryKey: queries.printTemplates.list({}).queryKey })
113-
toast.success('Template restored from default')
114-
setRestoreDialogOpen(false)
115-
setSelectedDefault(null)
116-
setSetAsDefault(false)
117-
if (result) {
118-
navigate(`/settings/print-templates/${result.id}`)
119-
}
95+
toast.success('Templates reset to defaults')
96+
setResetDialogOpen(false)
12097
},
12198
onError: () => {
122-
toast.error('Failed to restore template')
99+
toast.error('Failed to reset templates')
123100
}
124101
})
125102

@@ -142,16 +119,12 @@ export const PrintTemplatesSettings = () => {
142119
setDefaultMutation.mutate({ id: template.id, type: template.type })
143120
}
144121

145-
const handleRestore = (defaultTemplate: DefaultPrintTemplate) => {
146-
setSelectedDefault(defaultTemplate)
147-
setSetAsDefault(false)
148-
setRestoreDialogOpen(true)
122+
const handleReset = () => {
123+
setResetDialogOpen(true)
149124
}
150125

151-
const confirmRestore = () => {
152-
if (selectedDefault) {
153-
restoreMutation.mutate({ key: selectedDefault.key, setAsDefault })
154-
}
126+
const confirmReset = () => {
127+
resetMutation.mutate()
155128
}
156129

157130
const TemplateCard = ({ template }: { template: PrintTemplate }) => (
@@ -317,24 +290,10 @@ export const PrintTemplatesSettings = () => {
317290
</div>
318291
</div>
319292
<div className="flex items-center gap-2">
320-
{defaultTemplates && defaultTemplates.length > 0 && (
321-
<DropdownMenu>
322-
<DropdownMenuTrigger asChild>
323-
<Button variant="outline" size="sm">
324-
<RotateCcw className="h-4 w-4 mr-2" />
325-
Restore Default
326-
</Button>
327-
</DropdownMenuTrigger>
328-
<DropdownMenuContent align="end">
329-
{defaultTemplates.map((dt) => (
330-
<DropdownMenuItem key={dt.key} onClick={() => handleRestore(dt)}>
331-
<FileText className="h-4 w-4 mr-2" />
332-
{dt.name}
333-
</DropdownMenuItem>
334-
))}
335-
</DropdownMenuContent>
336-
</DropdownMenu>
337-
)}
293+
<Button variant="outline" size="sm" onClick={handleReset}>
294+
<RotateCcw className="h-4 w-4 mr-2" />
295+
Reset to Defaults
296+
</Button>
338297
{hasTemplates && (
339298
<Button size="sm" onClick={() => navigate('/settings/print-templates/new')}>
340299
<Plus className="h-4 w-4 mr-2" />
@@ -403,38 +362,27 @@ export const PrintTemplatesSettings = () => {
403362
</AlertDialogContent>
404363
</AlertDialog>
405364

406-
{/* Restore Default Dialog */}
407-
<Dialog open={restoreDialogOpen} onOpenChange={setRestoreDialogOpen}>
408-
<DialogContent>
409-
<DialogHeader>
410-
<DialogTitle>Restore Default Template</DialogTitle>
411-
<DialogDescription>
412-
This will create a new template based on the default &ldquo;{selectedDefault?.name}
413-
&rdquo;.
414-
</DialogDescription>
415-
</DialogHeader>
416-
<div className="py-4">
417-
<div className="flex items-center space-x-2">
418-
<Checkbox
419-
id="setAsDefault"
420-
checked={setAsDefault}
421-
onCheckedChange={(checked) => setSetAsDefault(checked === true)}
422-
/>
423-
<Label htmlFor="setAsDefault" className="text-sm font-normal">
424-
Set as default template for {selectedDefault?.type} notes
425-
</Label>
426-
</div>
427-
</div>
428-
<DialogFooter>
429-
<Button variant="outline" onClick={() => setRestoreDialogOpen(false)}>
430-
Cancel
431-
</Button>
432-
<Button onClick={confirmRestore} disabled={restoreMutation.isPending}>
433-
{restoreMutation.isPending ? 'Restoring...' : 'Restore Template'}
434-
</Button>
435-
</DialogFooter>
436-
</DialogContent>
437-
</Dialog>
365+
{/* Reset to Defaults Confirmation Dialog */}
366+
<AlertDialog open={resetDialogOpen} onOpenChange={setResetDialogOpen}>
367+
<AlertDialogContent>
368+
<AlertDialogHeader>
369+
<AlertDialogTitle>Reset to Default Templates</AlertDialogTitle>
370+
<AlertDialogDescription>
371+
This will delete all your custom templates and restore the original default templates.
372+
This action cannot be undone.
373+
</AlertDialogDescription>
374+
</AlertDialogHeader>
375+
<AlertDialogFooter>
376+
<AlertDialogCancel>Cancel</AlertDialogCancel>
377+
<AlertDialogAction
378+
onClick={confirmReset}
379+
disabled={resetMutation.isPending}
380+
>
381+
{resetMutation.isPending ? 'Resetting...' : 'Reset Templates'}
382+
</AlertDialogAction>
383+
</AlertDialogFooter>
384+
</AlertDialogContent>
385+
</AlertDialog>
438386
</div>
439387
)
440388
}

src/renderer/src/routes/settings/print-template-editor.tsx

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -148,15 +148,26 @@ export const PrintTemplateEditorPage = () => {
148148
<ArrowLeft className="h-4 w-4" />
149149
</Button>
150150
<div className="flex items-center gap-3">
151-
<Input
152-
value={name}
153-
onChange={(e) => {
154-
setName(e.target.value)
155-
setIsDirty(true)
156-
}}
157-
placeholder="Template name"
158-
className="w-64 h-8 text-sm font-medium"
159-
/>
151+
<div className="flex flex-col gap-1">
152+
<Input
153+
value={name}
154+
onChange={(e) => {
155+
setName(e.target.value)
156+
setIsDirty(true)
157+
}}
158+
placeholder="Template name"
159+
className="w-64 h-8 text-sm font-medium"
160+
/>
161+
<Input
162+
value={description}
163+
onChange={(e) => {
164+
setDescription(e.target.value)
165+
setIsDirty(true)
166+
}}
167+
placeholder="Description (optional)"
168+
className="w-64 h-7 text-xs text-muted-foreground"
169+
/>
170+
</div>
160171
{isNew && (
161172
<Select
162173
value={templateType}

0 commit comments

Comments
 (0)