Conversation
📝 WalkthroughWalkthroughAdds a chat-specific branch to the ProGate modal content, extends ProGate type union with "template_duplicate", and implements template duplication via a new onDuplicate prop in TemplateEditor and a handler in TemplatesView. Locales file references updated and new datetime strings added; translations unchanged. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant TemplatesView
participant License
participant ProGateModal
participant TemplateService
participant TemplatesStore as Store
User->>TemplatesView: Click "Duplicate" in TemplateEditor
TemplatesView->>License: isValid()
alt License invalid
TemplatesView->>ProGateModal: Open(type="template_duplicate")
Note over ProGateModal: Shows pro-gate for duplication
TemplatesView-->>User: Exit (no duplication)
else License valid
TemplatesView->>TemplatesView: Build duplicated template\n(emoji/title/id/tags)
TemplatesView->>TemplateService: saveTemplate(duplicate)
TemplateService-->>TemplatesView: OK
TemplatesView->>Store: reloadTemplates()
TemplatesView->>Store: selectTemplate(newId)
TemplatesView->>TemplatesView: switchToEditor()
TemplatesView-->>User: Editor opened with copy
end
sequenceDiagram
autonumber
participant ProGateModal
participant getContent
ProGateModal->>getContent: with type
alt type == "template"
getContent-->>ProGateModal: Template creation message
else type == "chat"
getContent-->>ProGateModal: Chat-specific message
else default
getContent-->>ProGateModal: Template-duplication / default message
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
Status, Documentation and Community
|
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
apps/desktop/src/components/settings/views/template.tsx (3)
85-88: Remove debug logs (noise + potential PII leak).These logs can leak user/template data and clutter console.
- console.log("now in template editor"); - console.log("template: ", template); - console.log("isBuiltinTemplate: ", isBuiltinTemplate);
90-97: Emoji regex is fragile; prefer a more robust matcher.\p{Emoji} support differs across engines and won’t match multi-codepoint sequences. Use Extended_Pictographic (broader support) or an emoji-regex.
- const extractEmojiFromTitle = (title: string) => { - const emojiMatch = title.match(/^(\p{Emoji})\s*/u); - return emojiMatch ? emojiMatch[1] : "📄"; - }; + const extractEmojiFromTitle = (title: string) => { + // Heuristic: pick the first extended pictographic at start; fallback default + const m = title.match(/^(\p{Extended_Pictographic}\uFE0F?)\s*/u); + return m ? m[1] : "📄"; + }; - const getTitleWithoutEmoji = (title: string) => { - return title.replace(/^(\p{Emoji})\s*/u, ""); - }; + const getTitleWithoutEmoji = (title: string) => { + return title.replace(/^(\p{Extended_Pictographic}\uFE0F?)\s*/u, ""); + };If you want full RGI coverage, switch to the emoji-regex package.
198-226: Show “Duplicate” even for built-in/non-creator templates; keep “Delete” gated.Users often duplicate built-ins they can't edit/delete. Current isCreator guard hides the whole menu.
- {isCreator && ( - <DropdownMenu> + <DropdownMenu> <DropdownMenuTrigger asChild> <Button variant="outline" size="sm"> <MoreHorizontalIcon className="h-4 w-4" /> </Button> </DropdownMenuTrigger> <DropdownMenuContent align="end"> <DropdownMenuItem onClick={handleDuplicate} className="cursor-pointer"> <CopyIcon className="mr-2 h-4 w-4" /> <Trans>Duplicate</Trans> </DropdownMenuItem> - {/* Only show separator and delete option for custom templates */} - {!isBuiltinTemplate && ( + {/* Delete only for custom templates created by the user */} + {!isBuiltinTemplate && isCreator && ( <> <DropdownMenuSeparator /> <DropdownMenuItem onClick={handleDelete} className="text-destructive hover:bg-red-100 hover:text-red-600 cursor-pointer" > <TrashIcon className="mr-2 h-4 w-4" /> <Trans>Delete</Trans> </DropdownMenuItem> </> )} </DropdownMenuContent> - </DropdownMenu> - )} + </DropdownMenu>
🧹 Nitpick comments (4)
apps/desktop/src/components/pro-gate-modal/index.tsx (1)
81-83: Optional: localize modal copy.These strings bypass Lingui. Consider moving them to i18n to keep UX copy consistent with the rest of the app.
apps/desktop/src/components/settings/views/template.tsx (1)
155-156: Prune “what” comments.Comments explain what the UI does, not why. Remove or rewrite if a non-obvious rationale exists.
- {/* Emoji Selector - unchanged */} ... - {/* Only show separator and delete option for custom templates */}Also applies to: 211-213
apps/desktop/src/components/settings/views/templates.tsx (2)
221-226: Use the saved record returned from TemplateService.Avoid stale state; set selection from the persisted value.
- await TemplateService.saveTemplate(duplicatedTemplate); + const saved = await TemplateService.saveTemplate(duplicatedTemplate); @@ - setSelectedTemplate(duplicatedTemplate); + setSelectedTemplate(saved);
228-231: Enrich analytics payload for better observability.Add context like template_id and source ("editor" vs "list") if supported by the analytics SDK.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (6)
apps/desktop/src/components/pro-gate-modal/index.tsx(1 hunks)apps/desktop/src/components/pro-gate-modal/types.ts(1 hunks)apps/desktop/src/components/settings/views/template.tsx(3 hunks)apps/desktop/src/components/settings/views/templates.tsx(2 hunks)apps/desktop/src/locales/en/messages.po(28 hunks)apps/desktop/src/locales/ko/messages.po(28 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,ts,tsx,rs}
⚙️ CodeRabbit configuration file
**/*.{js,ts,tsx,rs}: 1. No error handling.
2. No unused imports, variables, or functions.
3. For comments, keep it minimal. It should be about "Why", not "What".
Files:
apps/desktop/src/components/pro-gate-modal/types.tsapps/desktop/src/components/pro-gate-modal/index.tsxapps/desktop/src/components/settings/views/template.tsxapps/desktop/src/components/settings/views/templates.tsx
🧬 Code graph analysis (3)
apps/desktop/src/components/pro-gate-modal/types.ts (1)
apps/desktop/src/components/pro-gate-modal/index.tsx (1)
ProGateType(173-173)
apps/desktop/src/components/settings/views/template.tsx (1)
plugins/db/js/bindings.gen.ts (1)
Template(184-184)
apps/desktop/src/components/settings/views/templates.tsx (3)
plugins/db/js/bindings.gen.ts (1)
Template(184-184)apps/desktop/src/components/pro-gate-modal/service.ts (1)
showProGateModal(6-27)apps/desktop/src/utils/template-service.ts (1)
TemplateService(5-66)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: ci (macos, macos-latest)
- GitHub Check: ci (windows, windows-latest)
🔇 Additional comments (4)
apps/desktop/src/locales/ko/messages.po (1)
17-17: LGTM: reference realignments and new datetime keys only.No msgid/msgstr semantic changes detected. Keep KO in sync if new gating copy gets localized later.
Also applies to: 274-276, 467-471, 650-652, 675-678, 688-693, 710-713, 730-733, 746-749, 969-971, 1004-1007, 1146-1149, 1471-1474, 1512-1515, 1545-1549, 1746-1749
apps/desktop/src/locales/en/messages.po (1)
17-20: LGTM: adds datetime strings and updates source refs.Strings/placements look consistent; placeholders preserved.
Also applies to: 212-215, 467-471, 650-653, 675-678, 688-693, 710-713, 730-733, 746-749, 969-971, 1004-1007, 1146-1149, 1471-1474, 1512-1515, 1545-1549, 1746-1749
apps/desktop/src/components/settings/views/template.tsx (2)
24-26: Wiring for onDuplicate looks correct.Optional chaining avoids breaking older callers.
Also applies to: 76-78, 142-145
106-111: Maintain dependency ontemplate.idonly—syncing ontemplate.title/template.descriptionwould reset local edits on every prop updateLikely an incorrect or invalid review comment.
| } else if (type === "chat") { | ||
| return { | ||
| description: "4 messages are allowed per conversation for free users. Upgrade to pro for unlimited chat.", | ||
| }; | ||
| } else { | ||
| return { | ||
| description: "Template duplication is only available for pro users. Please upgrade your account to continue.", | ||
| }; | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Make branching exhaustive and explicit for "template_duplicate".
Replace the if/else chain with a switch that enumerates all ProGateType members to prevent future silent defaults.
Apply the diff suggested in types.ts review comment.
🤖 Prompt for AI Agents
In apps/desktop/src/components/pro-gate-modal/index.tsx around lines 20 to 28,
replace the current if/else chain for handling ProGateType values with a switch
statement that explicitly enumerates every ProGateType member (including "chat",
"template_duplicate" and any other members defined in types.ts), returning the
corresponding description for each case; add an explicit default that either
throws an error or uses a never-exhaustive-check helper so new enum values cause
a compile/runtime failure rather than silently falling back, and align wording
with the types.ts suggested diff.
| isOpen: boolean; | ||
| onClose: () => void; | ||
| type: "template" | "chat"; | ||
| type: "template" | "chat" | "template_duplicate"; |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Ensure exhaustive handling of the new ProGate type across call sites.
Adding "template_duplicate" is fine. Prefer explicit handling (no implicit default) wherever the type is branched on to avoid future silent fallthrough.
You can make getContent() in index.tsx exhaustive:
- const getContent = () => {
- if (type === "template") {
- return { description: "You've reached the custom template limit for free users. Please upgrade your account to continue." };
- } else if (type === "chat") {
- return { description: "4 messages are allowed per conversation for free users. Upgrade to pro for unlimited chat." };
- } else {
- return { description: "Template duplication is only available for pro users. Please upgrade your account to continue." };
- }
- };
+ const getContent = () => {
+ switch (type) {
+ case "template":
+ return { description: "You've reached the custom template limit for free users. Please upgrade your account to continue." };
+ case "chat":
+ return { description: "4 messages are allowed per conversation for free users. Upgrade to pro for unlimited chat." };
+ case "template_duplicate":
+ return { description: "Template duplication is only available for pro users. Please upgrade your account to continue." };
+ default: {
+ const _exhaustive: never = type;
+ return { description: "" };
+ }
+ }
+ };Run to find any non-exhaustive branches on ProGate type:
Also applies to: 7-7
🏁 Script executed:
#!/bin/bash
rg -nP --type=ts --type=tsx -C2 '\btype\s*===\s*"(template|chat|template_duplicate)"|switch\s*\(\s*type\s*\)' apps/desktop/srcLength of output: 156
🏁 Script executed:
#!/bin/bash
# Search for direct comparisons to ProGate type values and switch statements across .ts and .tsx files
rg -nP -C2 'type\s*===\s*"(template|chat|template_duplicate)"' -g '*.ts' -g '*.tsx' apps/desktop/src
rg -nP -C2 'switch\s*\(\s*type\s*\)' -g '*.ts' -g '*.tsx' apps/desktop/srcLength of output: 1120
Use an exhaustive switch for getContent in pro-gate-modal/index.tsx
Replace the current if/else if/else chain with a switch (type) that has explicit cases for "template", "chat", and "template_duplicate", and a default branch assigning never to enforce exhaustiveness.
🤖 Prompt for AI Agents
In apps/desktop/src/components/pro-gate-modal/types.ts line 4 and
apps/desktop/src/components/pro-gate-modal/index.tsx around the getContent
implementation, replace the existing if/else if/else chain with a switch(type)
that has explicit cases for "template", "chat", and "template_duplicate"; in
each case return the appropriate content narrowing the props to that branch, and
add a default branch that assigns the variable to never (e.g., const
_exhaustiveCheck: never = type) to enforce exhaustiveness so the compiler fails
if the union changes.
| const handleDuplicateTemplate = async (template: Template) => { | ||
| try { |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Remove local try/catch; follow repo rule “No error handling.”
Let errors bubble to the caller/UI boundary or centralize in TemplateService.
- const handleDuplicateTemplate = async (template: Template) => {
- try {
+ const handleDuplicateTemplate = async (template: Template) => {
@@
- } catch (error) {
- console.error("Failed to duplicate template:", error);
- }
- };
+ };Also applies to: 232-235
🤖 Prompt for AI Agents
In apps/desktop/src/components/settings/views/templates.tsx around lines 199-200
(and also for the block at 232-235), remove the local try/catch wrappers in
handleDuplicateTemplate (and the other duplicated block) so errors are not
handled locally; instead let the async function return/throw normally so errors
bubble to the caller or the centralized TemplateService error boundary; if any
cleanup is required keep a finally block only, otherwise delete the catch and
its contents and ensure the function returns the Promise directly.
| if (!getLicense.data?.valid) { | ||
| analyticsCommands.event({ | ||
| event: "pro_license_required_template", | ||
| distinct_id: userId, | ||
| }); | ||
| await showProGateModal("template_duplicate"); | ||
| return; | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Align duplication gating with creation gating (respect free quota).
Creation checks !valid && customTemplates.length > 1 while duplication gates on any invalid license. Use the same threshold to keep UX consistent.
- if (!getLicense.data?.valid) {
+ if (!getLicense.data?.valid && customTemplates.length > 1) {
analyticsCommands.event({
event: "pro_license_required_template",
distinct_id: userId,
});
await showProGateModal("template_duplicate");
return;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (!getLicense.data?.valid) { | |
| analyticsCommands.event({ | |
| event: "pro_license_required_template", | |
| distinct_id: userId, | |
| }); | |
| await showProGateModal("template_duplicate"); | |
| return; | |
| } | |
| if (!getLicense.data?.valid && customTemplates.length > 1) { | |
| analyticsCommands.event({ | |
| event: "pro_license_required_template", | |
| distinct_id: userId, | |
| }); | |
| await showProGateModal("template_duplicate"); | |
| return; | |
| } |
🤖 Prompt for AI Agents
In apps/desktop/src/components/settings/views/templates.tsx around lines 201 to
208, the duplication gating currently blocks all users without a valid license
but creation gating only blocks when the user is over the free quota (i.e.,
!valid && customTemplates.length > 1); update the duplication check to use the
same threshold so it only triggers analytics/event and showProGateModal when
getLicense.data?.valid is false AND customTemplates.length > 1, matching the
creation logic and keeping the UX consistent.
| template={selectedTemplate} | ||
| onTemplateUpdate={handleTemplateUpdate} | ||
| onDelete={handleTemplateDeleteFromEditor} | ||
| onDuplicate={handleDuplicateTemplate} |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Verify TemplateEditor prop contract and unify duplication paths.
- Ensure TemplateEditor accepts
onDuplicate?: (t: Template) => voidand wires it to its UI. - Route TemplateCard’s “Clone” to this same handler to avoid two divergent code paths (
handleCloneTemplatevshandleDuplicateTemplate) and to keep gating consistent. Example updates (outside this hunk):- custom list:
onClone={() => handleDuplicateTemplate(template)} - builtin list:
onClone={() => handleDuplicateTemplate(template)}
- custom list:
- Afterwards, delete
handleCloneTemplate.
🏁 Script executed:
#!/bin/bash
# Verify ProGate type supports "template_duplicate"
rg -nP '"template_duplicate"|ProGateType' apps/desktop/src
# Verify TemplateEditor prop includes onDuplicate and is used
rg -nP -C3 'onDuplicate\??\s*:\s*\(template:\s*Template' apps/desktop/src
rg -nP -C3 'export default function TemplateEditor|interface .*Props|type .*Props' apps/desktop/src/components
# Ensure only one duplicate handler exists in this file
rg -nP 'handleDuplicateTemplate\s*=\s*async' apps/desktop/src/components/settings/views/templates.tsxLength of output: 65257
results:
apps/desktop/src/components/settings/views/templates.tsx:150: const handleCloneTemplate = async (template: Template) => {
apps/desktop/src/components/settings/views/templates.tsx:250: onClone={() => handleCloneTemplate(template)}
The search confirms that handleCloneTemplate is still defined and used within templates.tsx at lines 150 and 250, and onClone prop is wired to handleCloneTemplate. The review comment’s suggestion to unify the duplication paths by routing onClone to handleDuplicateTemplate and then removing handleCloneTemplate remains valid.
Unify duplication handlers
- In
apps/desktop/src/components/settings/views/templates.tsx, change allonClone={() => handleCloneTemplate(template)}(usages around line 250) toonClone={() => handleDuplicateTemplate(template)}and delete thehandleCloneTemplatedefinition (around line 150). - In
TemplateEditor(inapps/desktop/src/components/settings/views/template.tsx), destructure and call itsonDuplicateprop in the UI so the “Duplicate” action useshandleDuplicateTemplate.
🤖 Prompt for AI Agents
In apps/desktop/src/components/settings/views/templates.tsx around lines
250-262, replace all usages of onClone={() => handleCloneTemplate(template)}
with onClone={() => handleDuplicateTemplate(template)} and remove the now-unused
handleCloneTemplate function definition located around line 150; in
apps/desktop/src/components/settings/views/template.tsx (TemplateEditor) update
the component props to destructure onDuplicate and invoke onDuplicate where the
“Duplicate” action is rendered so the Duplicate UI calls the passed-in
handleDuplicateTemplate handler. Ensure imports/prop types are updated and no
references to handleCloneTemplate remain.
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (3)
apps/desktop/src/components/settings/views/template.tsx(4 hunks)apps/desktop/src/locales/en/messages.po(28 hunks)apps/desktop/src/locales/ko/messages.po(28 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/desktop/src/locales/en/messages.po
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,ts,tsx,rs}
⚙️ CodeRabbit configuration file
**/*.{js,ts,tsx,rs}: 1. No error handling.
2. No unused imports, variables, or functions.
3. For comments, keep it minimal. It should be about "Why", not "What".
Files:
apps/desktop/src/components/settings/views/template.tsx
🧬 Code graph analysis (1)
apps/desktop/src/components/settings/views/template.tsx (2)
plugins/db/js/bindings.gen.ts (1)
Template(184-184)packages/ui/src/components/ui/button.tsx (1)
Button(37-89)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: ci (macos, macos-latest)
- GitHub Check: ci (windows, windows-latest)
🔇 Additional comments (5)
apps/desktop/src/components/settings/views/template.tsx (3)
16-16: Add onDuplicate prop — LGTMType looks correct and aligns with Template shape.
68-70: Prop destructuring — LGTMOptional prop handled safely with optional chaining downstream.
134-137: Disable duplicate button during processing or confirm backend idempotency
The duplicate handler immediately callsTemplateService.saveTemplatewithout disabling the button, so rapid clicks can spawn concurrent duplicate‐creation requests. Either disable the Duplicate button until the operation completes or verify that the backend API safely deduplicates concurrent calls.apps/desktop/src/locales/ko/messages.po (2)
22-209: New datetime keys added — LGTMReferences added; translations left empty as expected for now.
335-337: Recompile message catalogs and verify translations — only reference locations changed; regenerate the compiled catalogs and ensure any newly added msgids (e.g. “Add a system instruction…”) have corresponding translations.
| {isCreator && ( | ||
| <DropdownMenu> | ||
| <DropdownMenuTrigger asChild> | ||
| <Button variant="outline" size="sm"> | ||
| <MoreHorizontalIcon className="h-4 w-4" /> | ||
| </Button> | ||
| </DropdownMenuTrigger> | ||
| <DropdownMenuContent align="end"> | ||
| <DropdownMenuItem onClick={handleDuplicate} className="cursor-pointer"> | ||
| <CopyIcon className="mr-2 h-4 w-4" /> | ||
| <Trans>Duplicate</Trans> | ||
| </DropdownMenuItem> | ||
|
|
||
| {/* Only show separator and delete option for custom templates */} | ||
| {!isBuiltinTemplate && ( | ||
| <> | ||
| <DropdownMenuSeparator /> | ||
| <DropdownMenuItem | ||
| onClick={handleDelete} | ||
| className="text-destructive hover:bg-red-100 hover:text-red-600 cursor-pointer" | ||
| > | ||
| <TrashIcon className="mr-2 h-4 w-4" /> | ||
| <Trans>Delete</Trans> | ||
| </DropdownMenuItem> | ||
| </> | ||
| <div className="flex gap-2"> | ||
| {isBuiltinTemplate | ||
| ? ( | ||
| <Button variant="outline" size="sm" onClick={handleDuplicate}> | ||
| <Trans>Duplicate</Trans> | ||
| </Button> | ||
| ) | ||
| : ( | ||
| <Button | ||
| variant="outline" | ||
| size="sm" | ||
| onClick={handleDelete} | ||
| className="text-destructive hover:bg-red-50 hover:text-red-600 hover:border-red-200" | ||
| > | ||
| <Trans>Delete</Trans> | ||
| </Button> | ||
| )} | ||
| </DropdownMenuContent> | ||
| </DropdownMenu> | ||
| </div> | ||
| )} |
There was a problem hiding this comment.
Duplicate button hidden for built-ins when user isn’t creator; avoid inert buttons
Showing Duplicate behind isCreator likely hides it for built-ins owned by the app. Also hide action buttons when handlers are absent to avoid no-ops.
Apply this diff:
- {isCreator && (
- <div className="flex gap-2">
- {isBuiltinTemplate
- ? (
- <Button variant="outline" size="sm" onClick={handleDuplicate}>
- <Trans>Duplicate</Trans>
- </Button>
- )
- : (
- <Button
- variant="outline"
- size="sm"
- onClick={handleDelete}
- className="text-destructive hover:bg-red-50 hover:text-red-600 hover:border-red-200"
- >
- <Trans>Delete</Trans>
- </Button>
- )}
- </div>
- )}
+ {((isBuiltinTemplate && !!onDuplicate) || (!isBuiltinTemplate && isCreator && !!onDelete)) ? (
+ <div className="flex gap-2">
+ {isBuiltinTemplate && onDuplicate && (
+ <Button variant="outline" size="sm" onClick={handleDuplicate}>
+ <Trans>Duplicate</Trans>
+ </Button>
+ )}
+ {!isBuiltinTemplate && isCreator && onDelete && (
+ <Button
+ variant="outline"
+ size="sm"
+ onClick={handleDelete}
+ className="text-destructive hover:bg-red-50 hover:text-red-600 hover:border-red-200"
+ >
+ <Trans>Delete</Trans>
+ </Button>
+ )}
+ </div>
+ ) : null}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| {isCreator && ( | |
| <DropdownMenu> | |
| <DropdownMenuTrigger asChild> | |
| <Button variant="outline" size="sm"> | |
| <MoreHorizontalIcon className="h-4 w-4" /> | |
| </Button> | |
| </DropdownMenuTrigger> | |
| <DropdownMenuContent align="end"> | |
| <DropdownMenuItem onClick={handleDuplicate} className="cursor-pointer"> | |
| <CopyIcon className="mr-2 h-4 w-4" /> | |
| <Trans>Duplicate</Trans> | |
| </DropdownMenuItem> | |
| {/* Only show separator and delete option for custom templates */} | |
| {!isBuiltinTemplate && ( | |
| <> | |
| <DropdownMenuSeparator /> | |
| <DropdownMenuItem | |
| onClick={handleDelete} | |
| className="text-destructive hover:bg-red-100 hover:text-red-600 cursor-pointer" | |
| > | |
| <TrashIcon className="mr-2 h-4 w-4" /> | |
| <Trans>Delete</Trans> | |
| </DropdownMenuItem> | |
| </> | |
| <div className="flex gap-2"> | |
| {isBuiltinTemplate | |
| ? ( | |
| <Button variant="outline" size="sm" onClick={handleDuplicate}> | |
| <Trans>Duplicate</Trans> | |
| </Button> | |
| ) | |
| : ( | |
| <Button | |
| variant="outline" | |
| size="sm" | |
| onClick={handleDelete} | |
| className="text-destructive hover:bg-red-50 hover:text-red-600 hover:border-red-200" | |
| > | |
| <Trans>Delete</Trans> | |
| </Button> | |
| )} | |
| </DropdownMenuContent> | |
| </DropdownMenu> | |
| </div> | |
| )} | |
| {((isBuiltinTemplate && !!onDuplicate) || (!isBuiltinTemplate && isCreator && !!onDelete)) ? ( | |
| <div className="flex gap-2"> | |
| {isBuiltinTemplate && onDuplicate && ( | |
| <Button variant="outline" size="sm" onClick={handleDuplicate}> | |
| <Trans>Duplicate</Trans> | |
| </Button> | |
| )} | |
| {!isBuiltinTemplate && isCreator && onDelete && ( | |
| <Button | |
| variant="outline" | |
| size="sm" | |
| onClick={handleDelete} | |
| className="text-destructive hover:bg-red-50 hover:text-red-600 hover:border-red-200" | |
| > | |
| <Trans>Delete</Trans> | |
| </Button> | |
| )} | |
| </div> | |
| ) : null} |
🤖 Prompt for AI Agents
In apps/desktop/src/components/settings/views/template.tsx around lines 190-209,
the current conditional shows the action wrapper only when isCreator, which
hides the Duplicate button for built-in templates and can render inert buttons
when handlers are missing; change the rendering so the Duplicate button is shown
when the template is built-in and a handleDuplicate handler exists, and show the
Delete button when the user is the creator and a handleDelete handler exists;
also only render the surrounding action container if at least one visible button
will be rendered to avoid empty/no-op controls.
No description provided.