Files
next-ai-draw-io/lib/template-storage.ts

386 lines
11 KiB
TypeScript
Raw Permalink Normal View History

feat: add personal My Templates library alongside Quick Examples (#773) * 增加了ralph自动化编程梳理 * feat: US-001 - 为模板库建立独立的 IndexedDB 存储层 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-002 - 在空聊天状态用我的模板库替换官方示例 - 将 ChatLobby 中的 Quick Examples 替换为 TemplatePanel - 当没有历史会话时,展示完整的模板库面板 - 当有历史会话时,展示可折叠的 "My Templates" 区域 - 使用 TemplatePanel 组件展示用户的个人模板库 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-004 - Provide template creation flow - Create TemplateCreateDialog component with form fields for prompt, title, description, tags, and pinned - Add i18n translations for template creation UI in en, zh, zh-Hant, ja - Update TemplatePanel to integrate the create dialog - Support initialPrompt prop for pre-filling from current input - Validate required prompt field (empty prompt not allowed) - Auto-generate default title from first 20 chars of Pin templates appear at top of list Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-005 - 为模板卡片提供编辑、删除和复制操作 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-006 - Send template directly on click and record usage statistics - Implement click-to-send template functionality with confirmation dialog - Add clickCount and runCount increment logic - Display runCount and lastUsedAt on template card - Add i18n translations for confirmation dialog (en, zh, zh-Hant, ja) - Pass onSendTemplate and currentInput props through component hierarchy Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-007 - Support template search, pin and default sorting - Add search bar to TemplatePanel with real-time filtering by title, description, and tags - Add pin/unpin toggle button on template cards (uses Bookmark icon with fill indicator) - Search uses existing searchTemplates function from template-storage - Sort uses existing sortTemplates function (pinned desc, runCount desc, lastUsedAt desc, updatedAt desc) - Show empty state with Search icon when search returns no results - List re-sorts immediately after pin/unpin toggle - Add i18n keys: searchPlaceholder, searchNoResults, pin, unpin for all 4 languages Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-008 - Support saving current input as template Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-009 - Support saving historical user message as template - Add "Save as Template" button to user messages - Pre-fill prompt with original user message text - Only show on user messages,- Dialog opens TemplateCreateDialog on click - Template appears in list immediately after saving Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-010 - Support template import and export Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: remove local-only dirs from git tracking (.agents, .cursor, scripts, screenshots) These directories contain local IDE configs, agent scripts, and dev tooling that should not be part of the upstream repository. Added them to .gitignore to prevent future accidental commits. * chore: remove AGENTS.md from git tracking * fix: add missing i18n keys for template export/import (en/zh/zh-Hant/ja) * fix: review fixes for my-templates PR - Fix fragile querySelector("form") with id-based lookup - Add objectStoreNames.contains guards for IndexedDB upgrades - Remove duplicate TemplateSchema, import from template-storage - Revert contributor-specific .gitignore additions - Fix broken i18n placeholders and missing translations (zh/ja/zh-Hant) - Remove unused setFiles prop from ChatLobby - Remove tags feature (unnecessary complexity) - Improve template card layout: overlay icons on hover, align stats - Add break-all and overflow-hidden for long prompt text in dialogs - Move incrementClickCount into sendTemplate for accurate tracking - Use Intl.RelativeTimeFormat for locale-aware relative time * feat: restore Quick Examples panel and add lobby panel visibility settings Bring back the ExamplePanel as a third collapsible section in ChatLobby alongside Recent Chats and My Templates. Add toggle switches in Settings to show/hide each lobby panel, persisted via localStorage. * fix: template send race condition, import defaults, and empty title bug - Use flushSync instead of setTimeout(0) in handleSendTemplate to ensure React state is flushed before form submission - Explicitly validate and default all fields in importTemplates to prevent undefined counters from malformed import JSON - Fall back to existing title in edit dialog instead of writing undefined * fix: address Copilot review comments and remove PRD file - Fix fallback formatLastUsed returning "Not used yet" for recent usage - Remove dead mounted flag in TemplatePanel useEffect - Respect panel visibility settings in no-history lobby state - Reject empty/whitespace titles in import validation - Trim title/prompt in importTemplates with default title fallback - Remove tasks/prd-template-library-replaces-examples.md from repo * fix: remove double sort, dead code, redundant stats, and break-all CSS - Remove redundant sortTemplates call in loadTemplates (already sorted by getAllTemplates) - Remove unused createEmptyTemplateInput and sortTemplates import - Show "Not used yet" only once for unused templates instead of twice - Use break-words instead of break-all on prompt textareas --------- Co-authored-by: 杜雷 <dreamfly@126.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-04-03 11:16:01 +08:00
import { type DBSchema, type IDBPDatabase, openDB } from "idb"
import { nanoid } from "nanoid"
// Constants
const DB_NAME = "next-ai-drawio-templates"
const DB_VERSION = 1
feat: add personal My Templates library alongside Quick Examples (#773) * 增加了ralph自动化编程梳理 * feat: US-001 - 为模板库建立独立的 IndexedDB 存储层 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-002 - 在空聊天状态用我的模板库替换官方示例 - 将 ChatLobby 中的 Quick Examples 替换为 TemplatePanel - 当没有历史会话时,展示完整的模板库面板 - 当有历史会话时,展示可折叠的 "My Templates" 区域 - 使用 TemplatePanel 组件展示用户的个人模板库 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-004 - Provide template creation flow - Create TemplateCreateDialog component with form fields for prompt, title, description, tags, and pinned - Add i18n translations for template creation UI in en, zh, zh-Hant, ja - Update TemplatePanel to integrate the create dialog - Support initialPrompt prop for pre-filling from current input - Validate required prompt field (empty prompt not allowed) - Auto-generate default title from first 20 chars of Pin templates appear at top of list Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-005 - 为模板卡片提供编辑、删除和复制操作 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-006 - Send template directly on click and record usage statistics - Implement click-to-send template functionality with confirmation dialog - Add clickCount and runCount increment logic - Display runCount and lastUsedAt on template card - Add i18n translations for confirmation dialog (en, zh, zh-Hant, ja) - Pass onSendTemplate and currentInput props through component hierarchy Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-007 - Support template search, pin and default sorting - Add search bar to TemplatePanel with real-time filtering by title, description, and tags - Add pin/unpin toggle button on template cards (uses Bookmark icon with fill indicator) - Search uses existing searchTemplates function from template-storage - Sort uses existing sortTemplates function (pinned desc, runCount desc, lastUsedAt desc, updatedAt desc) - Show empty state with Search icon when search returns no results - List re-sorts immediately after pin/unpin toggle - Add i18n keys: searchPlaceholder, searchNoResults, pin, unpin for all 4 languages Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-008 - Support saving current input as template Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-009 - Support saving historical user message as template - Add "Save as Template" button to user messages - Pre-fill prompt with original user message text - Only show on user messages,- Dialog opens TemplateCreateDialog on click - Template appears in list immediately after saving Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-010 - Support template import and export Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: remove local-only dirs from git tracking (.agents, .cursor, scripts, screenshots) These directories contain local IDE configs, agent scripts, and dev tooling that should not be part of the upstream repository. Added them to .gitignore to prevent future accidental commits. * chore: remove AGENTS.md from git tracking * fix: add missing i18n keys for template export/import (en/zh/zh-Hant/ja) * fix: review fixes for my-templates PR - Fix fragile querySelector("form") with id-based lookup - Add objectStoreNames.contains guards for IndexedDB upgrades - Remove duplicate TemplateSchema, import from template-storage - Revert contributor-specific .gitignore additions - Fix broken i18n placeholders and missing translations (zh/ja/zh-Hant) - Remove unused setFiles prop from ChatLobby - Remove tags feature (unnecessary complexity) - Improve template card layout: overlay icons on hover, align stats - Add break-all and overflow-hidden for long prompt text in dialogs - Move incrementClickCount into sendTemplate for accurate tracking - Use Intl.RelativeTimeFormat for locale-aware relative time * feat: restore Quick Examples panel and add lobby panel visibility settings Bring back the ExamplePanel as a third collapsible section in ChatLobby alongside Recent Chats and My Templates. Add toggle switches in Settings to show/hide each lobby panel, persisted via localStorage. * fix: template send race condition, import defaults, and empty title bug - Use flushSync instead of setTimeout(0) in handleSendTemplate to ensure React state is flushed before form submission - Explicitly validate and default all fields in importTemplates to prevent undefined counters from malformed import JSON - Fall back to existing title in edit dialog instead of writing undefined * fix: address Copilot review comments and remove PRD file - Fix fallback formatLastUsed returning "Not used yet" for recent usage - Remove dead mounted flag in TemplatePanel useEffect - Respect panel visibility settings in no-history lobby state - Reject empty/whitespace titles in import validation - Trim title/prompt in importTemplates with default title fallback - Remove tasks/prd-template-library-replaces-examples.md from repo * fix: remove double sort, dead code, redundant stats, and break-all CSS - Remove redundant sortTemplates call in loadTemplates (already sorted by getAllTemplates) - Remove unused createEmptyTemplateInput and sortTemplates import - Show "Not used yet" only once for unused templates instead of twice - Use break-words instead of break-all on prompt textareas --------- Co-authored-by: 杜雷 <dreamfly@126.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-04-03 11:16:01 +08:00
const STORE_NAME = "templates"
// Types
export interface Template {
id: string
title: string
prompt: string
description?: string
createdAt: number
updatedAt: number
clickCount: number
runCount: number
lastUsedAt: number
pinned: boolean
}
export type TemplateCreateInput = Pick<Template, "prompt"> &
Partial<
Omit<
Template,
| "id"
| "createdAt"
| "updatedAt"
| "clickCount"
| "runCount"
| "lastUsedAt"
>
>
interface TemplateDB extends DBSchema {
templates: {
key: string
value: Template
indexes: {
"by-updated": number
"by-pinned": number
"by-run-count": number
"by-last-used": number
}
}
}
// Default title: first 20 chars of trimmed prompt, with ellipsis if truncated
const DEFAULT_TITLE_MAX_LENGTH = 20
export function generateDefaultTitle(prompt: string): string {
const trimmed = prompt.trim()
if (trimmed.length <= DEFAULT_TITLE_MAX_LENGTH) return trimmed
return trimmed.slice(0, DEFAULT_TITLE_MAX_LENGTH).trim() + "..."
}
// Database singleton
let dbPromise: Promise<IDBPDatabase<TemplateDB>> | null = null
async function getDB(): Promise<IDBPDatabase<TemplateDB>> {
if (!dbPromise) {
dbPromise = openDB<TemplateDB>(DB_NAME, DB_VERSION, {
upgrade(db, oldVersion) {
if (oldVersion < 1) {
if (!db.objectStoreNames.contains(STORE_NAME)) {
const templateStore = db.createObjectStore(STORE_NAME, {
keyPath: "id",
})
templateStore.createIndex("by-updated", "updatedAt")
templateStore.createIndex("by-pinned", "pinned")
templateStore.createIndex("by-run-count", "runCount")
templateStore.createIndex("by-last-used", "lastUsedAt")
}
}
},
})
}
return dbPromise
}
// Check if IndexedDB is available
export function isIndexedDBAvailable(): boolean {
if (typeof window === "undefined") return false
try {
return "indexedDB" in window && window.indexedDB !== null
} catch {
return false
}
}
// CRUD Operations
export async function getAllTemplates(): Promise<Template[]> {
if (!isIndexedDBAvailable()) return []
try {
chore: remove dead code from previous #815 fix attempts (#841) PR #840 fixed issue #815 in the Electron main process via will-prevent-unload + preventDefault. The renderer-side workarounds introduced by previous fix attempts (#642, #648) are no longer needed and never had effect for their stated purpose. Removed: - configuration={ confirmExit: false } in DrawIoEmbed confirmExit is not a recognized draw.io config key (zero matches in jgraph/drawio source). This was always dead code. - modified=0 / keepmodified=0 URL parameters Per drawio source (app.min.js:14898), these only suppress the post-save modified-flag clearing — they do not prevent edits from setting editor.modified=true. They were ineffective for blocking beforeunload prompts and actually prevented draw.io from clearing its modified flag after save. - canPersist / canPersistChecked state and isIndexedDBUsable() probe Their only purpose was gating the dead config above. Removing them also removes a startup delay before the iframe renders. - handleDrawioAutoSave wrapper After PR #780 stripped its body, it was a pure passthrough useCallback. Now passes handleDiagramAutoSave directly to onAutoSave. - withDB / isClosingError / resetDBPromise / onversionchange / onclose / terminated handlers in lib/session-storage.ts and lib/template-storage.ts PR #648 added these to recover from 'IDBDatabase: connection is closing' errors that PR #642's first land caused via db.close() on the shared singleton. That bug was already fixed in c5de1a1 (re-land of #642), three minutes before PR #648 commits started. The retry handlers defend against multi-tab / version-change scenarios that cannot occur in this single-instance Electron app (requestSingleInstanceLock). template-storage.ts copied the same pattern when introduced by #773. Verified: - npx tsc --noEmit passes - Manual test in dev mode: session save/load works, template create works, diagram-only persistence works.
2026-05-21 08:37:14 +09:00
const db = await getDB()
const templates = await db.getAll(STORE_NAME)
return sortTemplates(templates)
feat: add personal My Templates library alongside Quick Examples (#773) * 增加了ralph自动化编程梳理 * feat: US-001 - 为模板库建立独立的 IndexedDB 存储层 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-002 - 在空聊天状态用我的模板库替换官方示例 - 将 ChatLobby 中的 Quick Examples 替换为 TemplatePanel - 当没有历史会话时,展示完整的模板库面板 - 当有历史会话时,展示可折叠的 "My Templates" 区域 - 使用 TemplatePanel 组件展示用户的个人模板库 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-004 - Provide template creation flow - Create TemplateCreateDialog component with form fields for prompt, title, description, tags, and pinned - Add i18n translations for template creation UI in en, zh, zh-Hant, ja - Update TemplatePanel to integrate the create dialog - Support initialPrompt prop for pre-filling from current input - Validate required prompt field (empty prompt not allowed) - Auto-generate default title from first 20 chars of Pin templates appear at top of list Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-005 - 为模板卡片提供编辑、删除和复制操作 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-006 - Send template directly on click and record usage statistics - Implement click-to-send template functionality with confirmation dialog - Add clickCount and runCount increment logic - Display runCount and lastUsedAt on template card - Add i18n translations for confirmation dialog (en, zh, zh-Hant, ja) - Pass onSendTemplate and currentInput props through component hierarchy Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-007 - Support template search, pin and default sorting - Add search bar to TemplatePanel with real-time filtering by title, description, and tags - Add pin/unpin toggle button on template cards (uses Bookmark icon with fill indicator) - Search uses existing searchTemplates function from template-storage - Sort uses existing sortTemplates function (pinned desc, runCount desc, lastUsedAt desc, updatedAt desc) - Show empty state with Search icon when search returns no results - List re-sorts immediately after pin/unpin toggle - Add i18n keys: searchPlaceholder, searchNoResults, pin, unpin for all 4 languages Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-008 - Support saving current input as template Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-009 - Support saving historical user message as template - Add "Save as Template" button to user messages - Pre-fill prompt with original user message text - Only show on user messages,- Dialog opens TemplateCreateDialog on click - Template appears in list immediately after saving Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-010 - Support template import and export Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: remove local-only dirs from git tracking (.agents, .cursor, scripts, screenshots) These directories contain local IDE configs, agent scripts, and dev tooling that should not be part of the upstream repository. Added them to .gitignore to prevent future accidental commits. * chore: remove AGENTS.md from git tracking * fix: add missing i18n keys for template export/import (en/zh/zh-Hant/ja) * fix: review fixes for my-templates PR - Fix fragile querySelector("form") with id-based lookup - Add objectStoreNames.contains guards for IndexedDB upgrades - Remove duplicate TemplateSchema, import from template-storage - Revert contributor-specific .gitignore additions - Fix broken i18n placeholders and missing translations (zh/ja/zh-Hant) - Remove unused setFiles prop from ChatLobby - Remove tags feature (unnecessary complexity) - Improve template card layout: overlay icons on hover, align stats - Add break-all and overflow-hidden for long prompt text in dialogs - Move incrementClickCount into sendTemplate for accurate tracking - Use Intl.RelativeTimeFormat for locale-aware relative time * feat: restore Quick Examples panel and add lobby panel visibility settings Bring back the ExamplePanel as a third collapsible section in ChatLobby alongside Recent Chats and My Templates. Add toggle switches in Settings to show/hide each lobby panel, persisted via localStorage. * fix: template send race condition, import defaults, and empty title bug - Use flushSync instead of setTimeout(0) in handleSendTemplate to ensure React state is flushed before form submission - Explicitly validate and default all fields in importTemplates to prevent undefined counters from malformed import JSON - Fall back to existing title in edit dialog instead of writing undefined * fix: address Copilot review comments and remove PRD file - Fix fallback formatLastUsed returning "Not used yet" for recent usage - Remove dead mounted flag in TemplatePanel useEffect - Respect panel visibility settings in no-history lobby state - Reject empty/whitespace titles in import validation - Trim title/prompt in importTemplates with default title fallback - Remove tasks/prd-template-library-replaces-examples.md from repo * fix: remove double sort, dead code, redundant stats, and break-all CSS - Remove redundant sortTemplates call in loadTemplates (already sorted by getAllTemplates) - Remove unused createEmptyTemplateInput and sortTemplates import - Show "Not used yet" only once for unused templates instead of twice - Use break-words instead of break-all on prompt textareas --------- Co-authored-by: 杜雷 <dreamfly@126.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-04-03 11:16:01 +08:00
} catch (error) {
console.error("Failed to get templates:", error)
return []
}
}
export async function getTemplate(id: string): Promise<Template | null> {
if (!isIndexedDBAvailable()) return null
try {
chore: remove dead code from previous #815 fix attempts (#841) PR #840 fixed issue #815 in the Electron main process via will-prevent-unload + preventDefault. The renderer-side workarounds introduced by previous fix attempts (#642, #648) are no longer needed and never had effect for their stated purpose. Removed: - configuration={ confirmExit: false } in DrawIoEmbed confirmExit is not a recognized draw.io config key (zero matches in jgraph/drawio source). This was always dead code. - modified=0 / keepmodified=0 URL parameters Per drawio source (app.min.js:14898), these only suppress the post-save modified-flag clearing — they do not prevent edits from setting editor.modified=true. They were ineffective for blocking beforeunload prompts and actually prevented draw.io from clearing its modified flag after save. - canPersist / canPersistChecked state and isIndexedDBUsable() probe Their only purpose was gating the dead config above. Removing them also removes a startup delay before the iframe renders. - handleDrawioAutoSave wrapper After PR #780 stripped its body, it was a pure passthrough useCallback. Now passes handleDiagramAutoSave directly to onAutoSave. - withDB / isClosingError / resetDBPromise / onversionchange / onclose / terminated handlers in lib/session-storage.ts and lib/template-storage.ts PR #648 added these to recover from 'IDBDatabase: connection is closing' errors that PR #642's first land caused via db.close() on the shared singleton. That bug was already fixed in c5de1a1 (re-land of #642), three minutes before PR #648 commits started. The retry handlers defend against multi-tab / version-change scenarios that cannot occur in this single-instance Electron app (requestSingleInstanceLock). template-storage.ts copied the same pattern when introduced by #773. Verified: - npx tsc --noEmit passes - Manual test in dev mode: session save/load works, template create works, diagram-only persistence works.
2026-05-21 08:37:14 +09:00
const db = await getDB()
return (await db.get(STORE_NAME, id)) || null
feat: add personal My Templates library alongside Quick Examples (#773) * 增加了ralph自动化编程梳理 * feat: US-001 - 为模板库建立独立的 IndexedDB 存储层 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-002 - 在空聊天状态用我的模板库替换官方示例 - 将 ChatLobby 中的 Quick Examples 替换为 TemplatePanel - 当没有历史会话时,展示完整的模板库面板 - 当有历史会话时,展示可折叠的 "My Templates" 区域 - 使用 TemplatePanel 组件展示用户的个人模板库 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-004 - Provide template creation flow - Create TemplateCreateDialog component with form fields for prompt, title, description, tags, and pinned - Add i18n translations for template creation UI in en, zh, zh-Hant, ja - Update TemplatePanel to integrate the create dialog - Support initialPrompt prop for pre-filling from current input - Validate required prompt field (empty prompt not allowed) - Auto-generate default title from first 20 chars of Pin templates appear at top of list Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-005 - 为模板卡片提供编辑、删除和复制操作 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-006 - Send template directly on click and record usage statistics - Implement click-to-send template functionality with confirmation dialog - Add clickCount and runCount increment logic - Display runCount and lastUsedAt on template card - Add i18n translations for confirmation dialog (en, zh, zh-Hant, ja) - Pass onSendTemplate and currentInput props through component hierarchy Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-007 - Support template search, pin and default sorting - Add search bar to TemplatePanel with real-time filtering by title, description, and tags - Add pin/unpin toggle button on template cards (uses Bookmark icon with fill indicator) - Search uses existing searchTemplates function from template-storage - Sort uses existing sortTemplates function (pinned desc, runCount desc, lastUsedAt desc, updatedAt desc) - Show empty state with Search icon when search returns no results - List re-sorts immediately after pin/unpin toggle - Add i18n keys: searchPlaceholder, searchNoResults, pin, unpin for all 4 languages Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-008 - Support saving current input as template Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-009 - Support saving historical user message as template - Add "Save as Template" button to user messages - Pre-fill prompt with original user message text - Only show on user messages,- Dialog opens TemplateCreateDialog on click - Template appears in list immediately after saving Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-010 - Support template import and export Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: remove local-only dirs from git tracking (.agents, .cursor, scripts, screenshots) These directories contain local IDE configs, agent scripts, and dev tooling that should not be part of the upstream repository. Added them to .gitignore to prevent future accidental commits. * chore: remove AGENTS.md from git tracking * fix: add missing i18n keys for template export/import (en/zh/zh-Hant/ja) * fix: review fixes for my-templates PR - Fix fragile querySelector("form") with id-based lookup - Add objectStoreNames.contains guards for IndexedDB upgrades - Remove duplicate TemplateSchema, import from template-storage - Revert contributor-specific .gitignore additions - Fix broken i18n placeholders and missing translations (zh/ja/zh-Hant) - Remove unused setFiles prop from ChatLobby - Remove tags feature (unnecessary complexity) - Improve template card layout: overlay icons on hover, align stats - Add break-all and overflow-hidden for long prompt text in dialogs - Move incrementClickCount into sendTemplate for accurate tracking - Use Intl.RelativeTimeFormat for locale-aware relative time * feat: restore Quick Examples panel and add lobby panel visibility settings Bring back the ExamplePanel as a third collapsible section in ChatLobby alongside Recent Chats and My Templates. Add toggle switches in Settings to show/hide each lobby panel, persisted via localStorage. * fix: template send race condition, import defaults, and empty title bug - Use flushSync instead of setTimeout(0) in handleSendTemplate to ensure React state is flushed before form submission - Explicitly validate and default all fields in importTemplates to prevent undefined counters from malformed import JSON - Fall back to existing title in edit dialog instead of writing undefined * fix: address Copilot review comments and remove PRD file - Fix fallback formatLastUsed returning "Not used yet" for recent usage - Remove dead mounted flag in TemplatePanel useEffect - Respect panel visibility settings in no-history lobby state - Reject empty/whitespace titles in import validation - Trim title/prompt in importTemplates with default title fallback - Remove tasks/prd-template-library-replaces-examples.md from repo * fix: remove double sort, dead code, redundant stats, and break-all CSS - Remove redundant sortTemplates call in loadTemplates (already sorted by getAllTemplates) - Remove unused createEmptyTemplateInput and sortTemplates import - Show "Not used yet" only once for unused templates instead of twice - Use break-words instead of break-all on prompt textareas --------- Co-authored-by: 杜雷 <dreamfly@126.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-04-03 11:16:01 +08:00
} catch (error) {
console.error("Failed to get template:", error)
return null
}
}
export async function createTemplate(
input: TemplateCreateInput,
): Promise<Template | null> {
if (!isIndexedDBAvailable()) return null
const prompt = input.prompt.trim()
if (!prompt) return null
const now = Date.now()
const template: Template = {
id: nanoid(),
title: input.title?.trim() || generateDefaultTitle(prompt),
prompt,
description: input.description?.trim() || undefined,
createdAt: now,
updatedAt: now,
clickCount: 0,
runCount: 0,
lastUsedAt: 0,
pinned: input.pinned ?? false,
}
try {
chore: remove dead code from previous #815 fix attempts (#841) PR #840 fixed issue #815 in the Electron main process via will-prevent-unload + preventDefault. The renderer-side workarounds introduced by previous fix attempts (#642, #648) are no longer needed and never had effect for their stated purpose. Removed: - configuration={ confirmExit: false } in DrawIoEmbed confirmExit is not a recognized draw.io config key (zero matches in jgraph/drawio source). This was always dead code. - modified=0 / keepmodified=0 URL parameters Per drawio source (app.min.js:14898), these only suppress the post-save modified-flag clearing — they do not prevent edits from setting editor.modified=true. They were ineffective for blocking beforeunload prompts and actually prevented draw.io from clearing its modified flag after save. - canPersist / canPersistChecked state and isIndexedDBUsable() probe Their only purpose was gating the dead config above. Removing them also removes a startup delay before the iframe renders. - handleDrawioAutoSave wrapper After PR #780 stripped its body, it was a pure passthrough useCallback. Now passes handleDiagramAutoSave directly to onAutoSave. - withDB / isClosingError / resetDBPromise / onversionchange / onclose / terminated handlers in lib/session-storage.ts and lib/template-storage.ts PR #648 added these to recover from 'IDBDatabase: connection is closing' errors that PR #642's first land caused via db.close() on the shared singleton. That bug was already fixed in c5de1a1 (re-land of #642), three minutes before PR #648 commits started. The retry handlers defend against multi-tab / version-change scenarios that cannot occur in this single-instance Electron app (requestSingleInstanceLock). template-storage.ts copied the same pattern when introduced by #773. Verified: - npx tsc --noEmit passes - Manual test in dev mode: session save/load works, template create works, diagram-only persistence works.
2026-05-21 08:37:14 +09:00
const db = await getDB()
await db.put(STORE_NAME, template)
feat: add personal My Templates library alongside Quick Examples (#773) * 增加了ralph自动化编程梳理 * feat: US-001 - 为模板库建立独立的 IndexedDB 存储层 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-002 - 在空聊天状态用我的模板库替换官方示例 - 将 ChatLobby 中的 Quick Examples 替换为 TemplatePanel - 当没有历史会话时,展示完整的模板库面板 - 当有历史会话时,展示可折叠的 "My Templates" 区域 - 使用 TemplatePanel 组件展示用户的个人模板库 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-004 - Provide template creation flow - Create TemplateCreateDialog component with form fields for prompt, title, description, tags, and pinned - Add i18n translations for template creation UI in en, zh, zh-Hant, ja - Update TemplatePanel to integrate the create dialog - Support initialPrompt prop for pre-filling from current input - Validate required prompt field (empty prompt not allowed) - Auto-generate default title from first 20 chars of Pin templates appear at top of list Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-005 - 为模板卡片提供编辑、删除和复制操作 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-006 - Send template directly on click and record usage statistics - Implement click-to-send template functionality with confirmation dialog - Add clickCount and runCount increment logic - Display runCount and lastUsedAt on template card - Add i18n translations for confirmation dialog (en, zh, zh-Hant, ja) - Pass onSendTemplate and currentInput props through component hierarchy Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-007 - Support template search, pin and default sorting - Add search bar to TemplatePanel with real-time filtering by title, description, and tags - Add pin/unpin toggle button on template cards (uses Bookmark icon with fill indicator) - Search uses existing searchTemplates function from template-storage - Sort uses existing sortTemplates function (pinned desc, runCount desc, lastUsedAt desc, updatedAt desc) - Show empty state with Search icon when search returns no results - List re-sorts immediately after pin/unpin toggle - Add i18n keys: searchPlaceholder, searchNoResults, pin, unpin for all 4 languages Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-008 - Support saving current input as template Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-009 - Support saving historical user message as template - Add "Save as Template" button to user messages - Pre-fill prompt with original user message text - Only show on user messages,- Dialog opens TemplateCreateDialog on click - Template appears in list immediately after saving Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-010 - Support template import and export Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: remove local-only dirs from git tracking (.agents, .cursor, scripts, screenshots) These directories contain local IDE configs, agent scripts, and dev tooling that should not be part of the upstream repository. Added them to .gitignore to prevent future accidental commits. * chore: remove AGENTS.md from git tracking * fix: add missing i18n keys for template export/import (en/zh/zh-Hant/ja) * fix: review fixes for my-templates PR - Fix fragile querySelector("form") with id-based lookup - Add objectStoreNames.contains guards for IndexedDB upgrades - Remove duplicate TemplateSchema, import from template-storage - Revert contributor-specific .gitignore additions - Fix broken i18n placeholders and missing translations (zh/ja/zh-Hant) - Remove unused setFiles prop from ChatLobby - Remove tags feature (unnecessary complexity) - Improve template card layout: overlay icons on hover, align stats - Add break-all and overflow-hidden for long prompt text in dialogs - Move incrementClickCount into sendTemplate for accurate tracking - Use Intl.RelativeTimeFormat for locale-aware relative time * feat: restore Quick Examples panel and add lobby panel visibility settings Bring back the ExamplePanel as a third collapsible section in ChatLobby alongside Recent Chats and My Templates. Add toggle switches in Settings to show/hide each lobby panel, persisted via localStorage. * fix: template send race condition, import defaults, and empty title bug - Use flushSync instead of setTimeout(0) in handleSendTemplate to ensure React state is flushed before form submission - Explicitly validate and default all fields in importTemplates to prevent undefined counters from malformed import JSON - Fall back to existing title in edit dialog instead of writing undefined * fix: address Copilot review comments and remove PRD file - Fix fallback formatLastUsed returning "Not used yet" for recent usage - Remove dead mounted flag in TemplatePanel useEffect - Respect panel visibility settings in no-history lobby state - Reject empty/whitespace titles in import validation - Trim title/prompt in importTemplates with default title fallback - Remove tasks/prd-template-library-replaces-examples.md from repo * fix: remove double sort, dead code, redundant stats, and break-all CSS - Remove redundant sortTemplates call in loadTemplates (already sorted by getAllTemplates) - Remove unused createEmptyTemplateInput and sortTemplates import - Show "Not used yet" only once for unused templates instead of twice - Use break-words instead of break-all on prompt textareas --------- Co-authored-by: 杜雷 <dreamfly@126.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-04-03 11:16:01 +08:00
return template
} catch (error) {
console.error("Failed to create template:", error)
return null
}
}
export async function updateTemplate(
id: string,
updates: Partial<Omit<Template, "id" | "createdAt">>,
): Promise<Template | null> {
if (!isIndexedDBAvailable()) return null
try {
chore: remove dead code from previous #815 fix attempts (#841) PR #840 fixed issue #815 in the Electron main process via will-prevent-unload + preventDefault. The renderer-side workarounds introduced by previous fix attempts (#642, #648) are no longer needed and never had effect for their stated purpose. Removed: - configuration={ confirmExit: false } in DrawIoEmbed confirmExit is not a recognized draw.io config key (zero matches in jgraph/drawio source). This was always dead code. - modified=0 / keepmodified=0 URL parameters Per drawio source (app.min.js:14898), these only suppress the post-save modified-flag clearing — they do not prevent edits from setting editor.modified=true. They were ineffective for blocking beforeunload prompts and actually prevented draw.io from clearing its modified flag after save. - canPersist / canPersistChecked state and isIndexedDBUsable() probe Their only purpose was gating the dead config above. Removing them also removes a startup delay before the iframe renders. - handleDrawioAutoSave wrapper After PR #780 stripped its body, it was a pure passthrough useCallback. Now passes handleDiagramAutoSave directly to onAutoSave. - withDB / isClosingError / resetDBPromise / onversionchange / onclose / terminated handlers in lib/session-storage.ts and lib/template-storage.ts PR #648 added these to recover from 'IDBDatabase: connection is closing' errors that PR #642's first land caused via db.close() on the shared singleton. That bug was already fixed in c5de1a1 (re-land of #642), three minutes before PR #648 commits started. The retry handlers defend against multi-tab / version-change scenarios that cannot occur in this single-instance Electron app (requestSingleInstanceLock). template-storage.ts copied the same pattern when introduced by #773. Verified: - npx tsc --noEmit passes - Manual test in dev mode: session save/load works, template create works, diagram-only persistence works.
2026-05-21 08:37:14 +09:00
const db = await getDB()
const existing = await db.get(STORE_NAME, id)
if (!existing) return null
const updated: Template = {
...existing,
...updates,
id: existing.id,
createdAt: existing.createdAt,
updatedAt: Date.now(),
}
await db.put(STORE_NAME, updated)
return updated
feat: add personal My Templates library alongside Quick Examples (#773) * 增加了ralph自动化编程梳理 * feat: US-001 - 为模板库建立独立的 IndexedDB 存储层 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-002 - 在空聊天状态用我的模板库替换官方示例 - 将 ChatLobby 中的 Quick Examples 替换为 TemplatePanel - 当没有历史会话时,展示完整的模板库面板 - 当有历史会话时,展示可折叠的 "My Templates" 区域 - 使用 TemplatePanel 组件展示用户的个人模板库 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-004 - Provide template creation flow - Create TemplateCreateDialog component with form fields for prompt, title, description, tags, and pinned - Add i18n translations for template creation UI in en, zh, zh-Hant, ja - Update TemplatePanel to integrate the create dialog - Support initialPrompt prop for pre-filling from current input - Validate required prompt field (empty prompt not allowed) - Auto-generate default title from first 20 chars of Pin templates appear at top of list Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-005 - 为模板卡片提供编辑、删除和复制操作 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-006 - Send template directly on click and record usage statistics - Implement click-to-send template functionality with confirmation dialog - Add clickCount and runCount increment logic - Display runCount and lastUsedAt on template card - Add i18n translations for confirmation dialog (en, zh, zh-Hant, ja) - Pass onSendTemplate and currentInput props through component hierarchy Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-007 - Support template search, pin and default sorting - Add search bar to TemplatePanel with real-time filtering by title, description, and tags - Add pin/unpin toggle button on template cards (uses Bookmark icon with fill indicator) - Search uses existing searchTemplates function from template-storage - Sort uses existing sortTemplates function (pinned desc, runCount desc, lastUsedAt desc, updatedAt desc) - Show empty state with Search icon when search returns no results - List re-sorts immediately after pin/unpin toggle - Add i18n keys: searchPlaceholder, searchNoResults, pin, unpin for all 4 languages Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-008 - Support saving current input as template Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-009 - Support saving historical user message as template - Add "Save as Template" button to user messages - Pre-fill prompt with original user message text - Only show on user messages,- Dialog opens TemplateCreateDialog on click - Template appears in list immediately after saving Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-010 - Support template import and export Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: remove local-only dirs from git tracking (.agents, .cursor, scripts, screenshots) These directories contain local IDE configs, agent scripts, and dev tooling that should not be part of the upstream repository. Added them to .gitignore to prevent future accidental commits. * chore: remove AGENTS.md from git tracking * fix: add missing i18n keys for template export/import (en/zh/zh-Hant/ja) * fix: review fixes for my-templates PR - Fix fragile querySelector("form") with id-based lookup - Add objectStoreNames.contains guards for IndexedDB upgrades - Remove duplicate TemplateSchema, import from template-storage - Revert contributor-specific .gitignore additions - Fix broken i18n placeholders and missing translations (zh/ja/zh-Hant) - Remove unused setFiles prop from ChatLobby - Remove tags feature (unnecessary complexity) - Improve template card layout: overlay icons on hover, align stats - Add break-all and overflow-hidden for long prompt text in dialogs - Move incrementClickCount into sendTemplate for accurate tracking - Use Intl.RelativeTimeFormat for locale-aware relative time * feat: restore Quick Examples panel and add lobby panel visibility settings Bring back the ExamplePanel as a third collapsible section in ChatLobby alongside Recent Chats and My Templates. Add toggle switches in Settings to show/hide each lobby panel, persisted via localStorage. * fix: template send race condition, import defaults, and empty title bug - Use flushSync instead of setTimeout(0) in handleSendTemplate to ensure React state is flushed before form submission - Explicitly validate and default all fields in importTemplates to prevent undefined counters from malformed import JSON - Fall back to existing title in edit dialog instead of writing undefined * fix: address Copilot review comments and remove PRD file - Fix fallback formatLastUsed returning "Not used yet" for recent usage - Remove dead mounted flag in TemplatePanel useEffect - Respect panel visibility settings in no-history lobby state - Reject empty/whitespace titles in import validation - Trim title/prompt in importTemplates with default title fallback - Remove tasks/prd-template-library-replaces-examples.md from repo * fix: remove double sort, dead code, redundant stats, and break-all CSS - Remove redundant sortTemplates call in loadTemplates (already sorted by getAllTemplates) - Remove unused createEmptyTemplateInput and sortTemplates import - Show "Not used yet" only once for unused templates instead of twice - Use break-words instead of break-all on prompt textareas --------- Co-authored-by: 杜雷 <dreamfly@126.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-04-03 11:16:01 +08:00
} catch (error) {
console.error("Failed to update template:", error)
return null
}
}
export async function deleteTemplate(id: string): Promise<boolean> {
if (!isIndexedDBAvailable()) return false
try {
chore: remove dead code from previous #815 fix attempts (#841) PR #840 fixed issue #815 in the Electron main process via will-prevent-unload + preventDefault. The renderer-side workarounds introduced by previous fix attempts (#642, #648) are no longer needed and never had effect for their stated purpose. Removed: - configuration={ confirmExit: false } in DrawIoEmbed confirmExit is not a recognized draw.io config key (zero matches in jgraph/drawio source). This was always dead code. - modified=0 / keepmodified=0 URL parameters Per drawio source (app.min.js:14898), these only suppress the post-save modified-flag clearing — they do not prevent edits from setting editor.modified=true. They were ineffective for blocking beforeunload prompts and actually prevented draw.io from clearing its modified flag after save. - canPersist / canPersistChecked state and isIndexedDBUsable() probe Their only purpose was gating the dead config above. Removing them also removes a startup delay before the iframe renders. - handleDrawioAutoSave wrapper After PR #780 stripped its body, it was a pure passthrough useCallback. Now passes handleDiagramAutoSave directly to onAutoSave. - withDB / isClosingError / resetDBPromise / onversionchange / onclose / terminated handlers in lib/session-storage.ts and lib/template-storage.ts PR #648 added these to recover from 'IDBDatabase: connection is closing' errors that PR #642's first land caused via db.close() on the shared singleton. That bug was already fixed in c5de1a1 (re-land of #642), three minutes before PR #648 commits started. The retry handlers defend against multi-tab / version-change scenarios that cannot occur in this single-instance Electron app (requestSingleInstanceLock). template-storage.ts copied the same pattern when introduced by #773. Verified: - npx tsc --noEmit passes - Manual test in dev mode: session save/load works, template create works, diagram-only persistence works.
2026-05-21 08:37:14 +09:00
const db = await getDB()
await db.delete(STORE_NAME, id)
feat: add personal My Templates library alongside Quick Examples (#773) * 增加了ralph自动化编程梳理 * feat: US-001 - 为模板库建立独立的 IndexedDB 存储层 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-002 - 在空聊天状态用我的模板库替换官方示例 - 将 ChatLobby 中的 Quick Examples 替换为 TemplatePanel - 当没有历史会话时,展示完整的模板库面板 - 当有历史会话时,展示可折叠的 "My Templates" 区域 - 使用 TemplatePanel 组件展示用户的个人模板库 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-004 - Provide template creation flow - Create TemplateCreateDialog component with form fields for prompt, title, description, tags, and pinned - Add i18n translations for template creation UI in en, zh, zh-Hant, ja - Update TemplatePanel to integrate the create dialog - Support initialPrompt prop for pre-filling from current input - Validate required prompt field (empty prompt not allowed) - Auto-generate default title from first 20 chars of Pin templates appear at top of list Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-005 - 为模板卡片提供编辑、删除和复制操作 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-006 - Send template directly on click and record usage statistics - Implement click-to-send template functionality with confirmation dialog - Add clickCount and runCount increment logic - Display runCount and lastUsedAt on template card - Add i18n translations for confirmation dialog (en, zh, zh-Hant, ja) - Pass onSendTemplate and currentInput props through component hierarchy Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-007 - Support template search, pin and default sorting - Add search bar to TemplatePanel with real-time filtering by title, description, and tags - Add pin/unpin toggle button on template cards (uses Bookmark icon with fill indicator) - Search uses existing searchTemplates function from template-storage - Sort uses existing sortTemplates function (pinned desc, runCount desc, lastUsedAt desc, updatedAt desc) - Show empty state with Search icon when search returns no results - List re-sorts immediately after pin/unpin toggle - Add i18n keys: searchPlaceholder, searchNoResults, pin, unpin for all 4 languages Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-008 - Support saving current input as template Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-009 - Support saving historical user message as template - Add "Save as Template" button to user messages - Pre-fill prompt with original user message text - Only show on user messages,- Dialog opens TemplateCreateDialog on click - Template appears in list immediately after saving Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-010 - Support template import and export Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: remove local-only dirs from git tracking (.agents, .cursor, scripts, screenshots) These directories contain local IDE configs, agent scripts, and dev tooling that should not be part of the upstream repository. Added them to .gitignore to prevent future accidental commits. * chore: remove AGENTS.md from git tracking * fix: add missing i18n keys for template export/import (en/zh/zh-Hant/ja) * fix: review fixes for my-templates PR - Fix fragile querySelector("form") with id-based lookup - Add objectStoreNames.contains guards for IndexedDB upgrades - Remove duplicate TemplateSchema, import from template-storage - Revert contributor-specific .gitignore additions - Fix broken i18n placeholders and missing translations (zh/ja/zh-Hant) - Remove unused setFiles prop from ChatLobby - Remove tags feature (unnecessary complexity) - Improve template card layout: overlay icons on hover, align stats - Add break-all and overflow-hidden for long prompt text in dialogs - Move incrementClickCount into sendTemplate for accurate tracking - Use Intl.RelativeTimeFormat for locale-aware relative time * feat: restore Quick Examples panel and add lobby panel visibility settings Bring back the ExamplePanel as a third collapsible section in ChatLobby alongside Recent Chats and My Templates. Add toggle switches in Settings to show/hide each lobby panel, persisted via localStorage. * fix: template send race condition, import defaults, and empty title bug - Use flushSync instead of setTimeout(0) in handleSendTemplate to ensure React state is flushed before form submission - Explicitly validate and default all fields in importTemplates to prevent undefined counters from malformed import JSON - Fall back to existing title in edit dialog instead of writing undefined * fix: address Copilot review comments and remove PRD file - Fix fallback formatLastUsed returning "Not used yet" for recent usage - Remove dead mounted flag in TemplatePanel useEffect - Respect panel visibility settings in no-history lobby state - Reject empty/whitespace titles in import validation - Trim title/prompt in importTemplates with default title fallback - Remove tasks/prd-template-library-replaces-examples.md from repo * fix: remove double sort, dead code, redundant stats, and break-all CSS - Remove redundant sortTemplates call in loadTemplates (already sorted by getAllTemplates) - Remove unused createEmptyTemplateInput and sortTemplates import - Show "Not used yet" only once for unused templates instead of twice - Use break-words instead of break-all on prompt textareas --------- Co-authored-by: 杜雷 <dreamfly@126.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-04-03 11:16:01 +08:00
return true
} catch (error) {
console.error("Failed to delete template:", error)
return false
}
}
export async function duplicateTemplate(
id: string,
copySuffix = "(copy)",
): Promise<Template | null> {
if (!isIndexedDBAvailable()) return null
try {
chore: remove dead code from previous #815 fix attempts (#841) PR #840 fixed issue #815 in the Electron main process via will-prevent-unload + preventDefault. The renderer-side workarounds introduced by previous fix attempts (#642, #648) are no longer needed and never had effect for their stated purpose. Removed: - configuration={ confirmExit: false } in DrawIoEmbed confirmExit is not a recognized draw.io config key (zero matches in jgraph/drawio source). This was always dead code. - modified=0 / keepmodified=0 URL parameters Per drawio source (app.min.js:14898), these only suppress the post-save modified-flag clearing — they do not prevent edits from setting editor.modified=true. They were ineffective for blocking beforeunload prompts and actually prevented draw.io from clearing its modified flag after save. - canPersist / canPersistChecked state and isIndexedDBUsable() probe Their only purpose was gating the dead config above. Removing them also removes a startup delay before the iframe renders. - handleDrawioAutoSave wrapper After PR #780 stripped its body, it was a pure passthrough useCallback. Now passes handleDiagramAutoSave directly to onAutoSave. - withDB / isClosingError / resetDBPromise / onversionchange / onclose / terminated handlers in lib/session-storage.ts and lib/template-storage.ts PR #648 added these to recover from 'IDBDatabase: connection is closing' errors that PR #642's first land caused via db.close() on the shared singleton. That bug was already fixed in c5de1a1 (re-land of #642), three minutes before PR #648 commits started. The retry handlers defend against multi-tab / version-change scenarios that cannot occur in this single-instance Electron app (requestSingleInstanceLock). template-storage.ts copied the same pattern when introduced by #773. Verified: - npx tsc --noEmit passes - Manual test in dev mode: session save/load works, template create works, diagram-only persistence works.
2026-05-21 08:37:14 +09:00
const db = await getDB()
const existing = await db.get(STORE_NAME, id)
if (!existing) return null
const now = Date.now()
const duplicate: Template = {
...existing,
id: nanoid(),
title: `${existing.title} ${copySuffix}`,
createdAt: now,
updatedAt: now,
clickCount: 0,
runCount: 0,
lastUsedAt: 0,
pinned: false,
}
await db.put(STORE_NAME, duplicate)
return duplicate
feat: add personal My Templates library alongside Quick Examples (#773) * 增加了ralph自动化编程梳理 * feat: US-001 - 为模板库建立独立的 IndexedDB 存储层 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-002 - 在空聊天状态用我的模板库替换官方示例 - 将 ChatLobby 中的 Quick Examples 替换为 TemplatePanel - 当没有历史会话时,展示完整的模板库面板 - 当有历史会话时,展示可折叠的 "My Templates" 区域 - 使用 TemplatePanel 组件展示用户的个人模板库 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-004 - Provide template creation flow - Create TemplateCreateDialog component with form fields for prompt, title, description, tags, and pinned - Add i18n translations for template creation UI in en, zh, zh-Hant, ja - Update TemplatePanel to integrate the create dialog - Support initialPrompt prop for pre-filling from current input - Validate required prompt field (empty prompt not allowed) - Auto-generate default title from first 20 chars of Pin templates appear at top of list Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-005 - 为模板卡片提供编辑、删除和复制操作 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-006 - Send template directly on click and record usage statistics - Implement click-to-send template functionality with confirmation dialog - Add clickCount and runCount increment logic - Display runCount and lastUsedAt on template card - Add i18n translations for confirmation dialog (en, zh, zh-Hant, ja) - Pass onSendTemplate and currentInput props through component hierarchy Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-007 - Support template search, pin and default sorting - Add search bar to TemplatePanel with real-time filtering by title, description, and tags - Add pin/unpin toggle button on template cards (uses Bookmark icon with fill indicator) - Search uses existing searchTemplates function from template-storage - Sort uses existing sortTemplates function (pinned desc, runCount desc, lastUsedAt desc, updatedAt desc) - Show empty state with Search icon when search returns no results - List re-sorts immediately after pin/unpin toggle - Add i18n keys: searchPlaceholder, searchNoResults, pin, unpin for all 4 languages Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-008 - Support saving current input as template Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-009 - Support saving historical user message as template - Add "Save as Template" button to user messages - Pre-fill prompt with original user message text - Only show on user messages,- Dialog opens TemplateCreateDialog on click - Template appears in list immediately after saving Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-010 - Support template import and export Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: remove local-only dirs from git tracking (.agents, .cursor, scripts, screenshots) These directories contain local IDE configs, agent scripts, and dev tooling that should not be part of the upstream repository. Added them to .gitignore to prevent future accidental commits. * chore: remove AGENTS.md from git tracking * fix: add missing i18n keys for template export/import (en/zh/zh-Hant/ja) * fix: review fixes for my-templates PR - Fix fragile querySelector("form") with id-based lookup - Add objectStoreNames.contains guards for IndexedDB upgrades - Remove duplicate TemplateSchema, import from template-storage - Revert contributor-specific .gitignore additions - Fix broken i18n placeholders and missing translations (zh/ja/zh-Hant) - Remove unused setFiles prop from ChatLobby - Remove tags feature (unnecessary complexity) - Improve template card layout: overlay icons on hover, align stats - Add break-all and overflow-hidden for long prompt text in dialogs - Move incrementClickCount into sendTemplate for accurate tracking - Use Intl.RelativeTimeFormat for locale-aware relative time * feat: restore Quick Examples panel and add lobby panel visibility settings Bring back the ExamplePanel as a third collapsible section in ChatLobby alongside Recent Chats and My Templates. Add toggle switches in Settings to show/hide each lobby panel, persisted via localStorage. * fix: template send race condition, import defaults, and empty title bug - Use flushSync instead of setTimeout(0) in handleSendTemplate to ensure React state is flushed before form submission - Explicitly validate and default all fields in importTemplates to prevent undefined counters from malformed import JSON - Fall back to existing title in edit dialog instead of writing undefined * fix: address Copilot review comments and remove PRD file - Fix fallback formatLastUsed returning "Not used yet" for recent usage - Remove dead mounted flag in TemplatePanel useEffect - Respect panel visibility settings in no-history lobby state - Reject empty/whitespace titles in import validation - Trim title/prompt in importTemplates with default title fallback - Remove tasks/prd-template-library-replaces-examples.md from repo * fix: remove double sort, dead code, redundant stats, and break-all CSS - Remove redundant sortTemplates call in loadTemplates (already sorted by getAllTemplates) - Remove unused createEmptyTemplateInput and sortTemplates import - Show "Not used yet" only once for unused templates instead of twice - Use break-words instead of break-all on prompt textareas --------- Co-authored-by: 杜雷 <dreamfly@126.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-04-03 11:16:01 +08:00
} catch (error) {
console.error("Failed to duplicate template:", error)
return null
}
}
// Usage tracking
export async function incrementClickCount(id: string): Promise<void> {
if (!isIndexedDBAvailable()) return
try {
chore: remove dead code from previous #815 fix attempts (#841) PR #840 fixed issue #815 in the Electron main process via will-prevent-unload + preventDefault. The renderer-side workarounds introduced by previous fix attempts (#642, #648) are no longer needed and never had effect for their stated purpose. Removed: - configuration={ confirmExit: false } in DrawIoEmbed confirmExit is not a recognized draw.io config key (zero matches in jgraph/drawio source). This was always dead code. - modified=0 / keepmodified=0 URL parameters Per drawio source (app.min.js:14898), these only suppress the post-save modified-flag clearing — they do not prevent edits from setting editor.modified=true. They were ineffective for blocking beforeunload prompts and actually prevented draw.io from clearing its modified flag after save. - canPersist / canPersistChecked state and isIndexedDBUsable() probe Their only purpose was gating the dead config above. Removing them also removes a startup delay before the iframe renders. - handleDrawioAutoSave wrapper After PR #780 stripped its body, it was a pure passthrough useCallback. Now passes handleDiagramAutoSave directly to onAutoSave. - withDB / isClosingError / resetDBPromise / onversionchange / onclose / terminated handlers in lib/session-storage.ts and lib/template-storage.ts PR #648 added these to recover from 'IDBDatabase: connection is closing' errors that PR #642's first land caused via db.close() on the shared singleton. That bug was already fixed in c5de1a1 (re-land of #642), three minutes before PR #648 commits started. The retry handlers defend against multi-tab / version-change scenarios that cannot occur in this single-instance Electron app (requestSingleInstanceLock). template-storage.ts copied the same pattern when introduced by #773. Verified: - npx tsc --noEmit passes - Manual test in dev mode: session save/load works, template create works, diagram-only persistence works.
2026-05-21 08:37:14 +09:00
const db = await getDB()
const template = await db.get(STORE_NAME, id)
if (!template) return
template.clickCount += 1
template.updatedAt = Date.now()
await db.put(STORE_NAME, template)
feat: add personal My Templates library alongside Quick Examples (#773) * 增加了ralph自动化编程梳理 * feat: US-001 - 为模板库建立独立的 IndexedDB 存储层 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-002 - 在空聊天状态用我的模板库替换官方示例 - 将 ChatLobby 中的 Quick Examples 替换为 TemplatePanel - 当没有历史会话时,展示完整的模板库面板 - 当有历史会话时,展示可折叠的 "My Templates" 区域 - 使用 TemplatePanel 组件展示用户的个人模板库 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-004 - Provide template creation flow - Create TemplateCreateDialog component with form fields for prompt, title, description, tags, and pinned - Add i18n translations for template creation UI in en, zh, zh-Hant, ja - Update TemplatePanel to integrate the create dialog - Support initialPrompt prop for pre-filling from current input - Validate required prompt field (empty prompt not allowed) - Auto-generate default title from first 20 chars of Pin templates appear at top of list Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-005 - 为模板卡片提供编辑、删除和复制操作 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-006 - Send template directly on click and record usage statistics - Implement click-to-send template functionality with confirmation dialog - Add clickCount and runCount increment logic - Display runCount and lastUsedAt on template card - Add i18n translations for confirmation dialog (en, zh, zh-Hant, ja) - Pass onSendTemplate and currentInput props through component hierarchy Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-007 - Support template search, pin and default sorting - Add search bar to TemplatePanel with real-time filtering by title, description, and tags - Add pin/unpin toggle button on template cards (uses Bookmark icon with fill indicator) - Search uses existing searchTemplates function from template-storage - Sort uses existing sortTemplates function (pinned desc, runCount desc, lastUsedAt desc, updatedAt desc) - Show empty state with Search icon when search returns no results - List re-sorts immediately after pin/unpin toggle - Add i18n keys: searchPlaceholder, searchNoResults, pin, unpin for all 4 languages Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-008 - Support saving current input as template Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-009 - Support saving historical user message as template - Add "Save as Template" button to user messages - Pre-fill prompt with original user message text - Only show on user messages,- Dialog opens TemplateCreateDialog on click - Template appears in list immediately after saving Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-010 - Support template import and export Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: remove local-only dirs from git tracking (.agents, .cursor, scripts, screenshots) These directories contain local IDE configs, agent scripts, and dev tooling that should not be part of the upstream repository. Added them to .gitignore to prevent future accidental commits. * chore: remove AGENTS.md from git tracking * fix: add missing i18n keys for template export/import (en/zh/zh-Hant/ja) * fix: review fixes for my-templates PR - Fix fragile querySelector("form") with id-based lookup - Add objectStoreNames.contains guards for IndexedDB upgrades - Remove duplicate TemplateSchema, import from template-storage - Revert contributor-specific .gitignore additions - Fix broken i18n placeholders and missing translations (zh/ja/zh-Hant) - Remove unused setFiles prop from ChatLobby - Remove tags feature (unnecessary complexity) - Improve template card layout: overlay icons on hover, align stats - Add break-all and overflow-hidden for long prompt text in dialogs - Move incrementClickCount into sendTemplate for accurate tracking - Use Intl.RelativeTimeFormat for locale-aware relative time * feat: restore Quick Examples panel and add lobby panel visibility settings Bring back the ExamplePanel as a third collapsible section in ChatLobby alongside Recent Chats and My Templates. Add toggle switches in Settings to show/hide each lobby panel, persisted via localStorage. * fix: template send race condition, import defaults, and empty title bug - Use flushSync instead of setTimeout(0) in handleSendTemplate to ensure React state is flushed before form submission - Explicitly validate and default all fields in importTemplates to prevent undefined counters from malformed import JSON - Fall back to existing title in edit dialog instead of writing undefined * fix: address Copilot review comments and remove PRD file - Fix fallback formatLastUsed returning "Not used yet" for recent usage - Remove dead mounted flag in TemplatePanel useEffect - Respect panel visibility settings in no-history lobby state - Reject empty/whitespace titles in import validation - Trim title/prompt in importTemplates with default title fallback - Remove tasks/prd-template-library-replaces-examples.md from repo * fix: remove double sort, dead code, redundant stats, and break-all CSS - Remove redundant sortTemplates call in loadTemplates (already sorted by getAllTemplates) - Remove unused createEmptyTemplateInput and sortTemplates import - Show "Not used yet" only once for unused templates instead of twice - Use break-words instead of break-all on prompt textareas --------- Co-authored-by: 杜雷 <dreamfly@126.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-04-03 11:16:01 +08:00
} catch (error) {
console.error("Failed to increment click count:", error)
}
}
export async function incrementRunCount(id: string): Promise<void> {
if (!isIndexedDBAvailable()) return
try {
chore: remove dead code from previous #815 fix attempts (#841) PR #840 fixed issue #815 in the Electron main process via will-prevent-unload + preventDefault. The renderer-side workarounds introduced by previous fix attempts (#642, #648) are no longer needed and never had effect for their stated purpose. Removed: - configuration={ confirmExit: false } in DrawIoEmbed confirmExit is not a recognized draw.io config key (zero matches in jgraph/drawio source). This was always dead code. - modified=0 / keepmodified=0 URL parameters Per drawio source (app.min.js:14898), these only suppress the post-save modified-flag clearing — they do not prevent edits from setting editor.modified=true. They were ineffective for blocking beforeunload prompts and actually prevented draw.io from clearing its modified flag after save. - canPersist / canPersistChecked state and isIndexedDBUsable() probe Their only purpose was gating the dead config above. Removing them also removes a startup delay before the iframe renders. - handleDrawioAutoSave wrapper After PR #780 stripped its body, it was a pure passthrough useCallback. Now passes handleDiagramAutoSave directly to onAutoSave. - withDB / isClosingError / resetDBPromise / onversionchange / onclose / terminated handlers in lib/session-storage.ts and lib/template-storage.ts PR #648 added these to recover from 'IDBDatabase: connection is closing' errors that PR #642's first land caused via db.close() on the shared singleton. That bug was already fixed in c5de1a1 (re-land of #642), three minutes before PR #648 commits started. The retry handlers defend against multi-tab / version-change scenarios that cannot occur in this single-instance Electron app (requestSingleInstanceLock). template-storage.ts copied the same pattern when introduced by #773. Verified: - npx tsc --noEmit passes - Manual test in dev mode: session save/load works, template create works, diagram-only persistence works.
2026-05-21 08:37:14 +09:00
const db = await getDB()
const template = await db.get(STORE_NAME, id)
if (!template) return
const now = Date.now()
template.runCount += 1
template.lastUsedAt = now
template.updatedAt = now
await db.put(STORE_NAME, template)
feat: add personal My Templates library alongside Quick Examples (#773) * 增加了ralph自动化编程梳理 * feat: US-001 - 为模板库建立独立的 IndexedDB 存储层 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-002 - 在空聊天状态用我的模板库替换官方示例 - 将 ChatLobby 中的 Quick Examples 替换为 TemplatePanel - 当没有历史会话时,展示完整的模板库面板 - 当有历史会话时,展示可折叠的 "My Templates" 区域 - 使用 TemplatePanel 组件展示用户的个人模板库 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-004 - Provide template creation flow - Create TemplateCreateDialog component with form fields for prompt, title, description, tags, and pinned - Add i18n translations for template creation UI in en, zh, zh-Hant, ja - Update TemplatePanel to integrate the create dialog - Support initialPrompt prop for pre-filling from current input - Validate required prompt field (empty prompt not allowed) - Auto-generate default title from first 20 chars of Pin templates appear at top of list Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-005 - 为模板卡片提供编辑、删除和复制操作 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-006 - Send template directly on click and record usage statistics - Implement click-to-send template functionality with confirmation dialog - Add clickCount and runCount increment logic - Display runCount and lastUsedAt on template card - Add i18n translations for confirmation dialog (en, zh, zh-Hant, ja) - Pass onSendTemplate and currentInput props through component hierarchy Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-007 - Support template search, pin and default sorting - Add search bar to TemplatePanel with real-time filtering by title, description, and tags - Add pin/unpin toggle button on template cards (uses Bookmark icon with fill indicator) - Search uses existing searchTemplates function from template-storage - Sort uses existing sortTemplates function (pinned desc, runCount desc, lastUsedAt desc, updatedAt desc) - Show empty state with Search icon when search returns no results - List re-sorts immediately after pin/unpin toggle - Add i18n keys: searchPlaceholder, searchNoResults, pin, unpin for all 4 languages Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-008 - Support saving current input as template Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-009 - Support saving historical user message as template - Add "Save as Template" button to user messages - Pre-fill prompt with original user message text - Only show on user messages,- Dialog opens TemplateCreateDialog on click - Template appears in list immediately after saving Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-010 - Support template import and export Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: remove local-only dirs from git tracking (.agents, .cursor, scripts, screenshots) These directories contain local IDE configs, agent scripts, and dev tooling that should not be part of the upstream repository. Added them to .gitignore to prevent future accidental commits. * chore: remove AGENTS.md from git tracking * fix: add missing i18n keys for template export/import (en/zh/zh-Hant/ja) * fix: review fixes for my-templates PR - Fix fragile querySelector("form") with id-based lookup - Add objectStoreNames.contains guards for IndexedDB upgrades - Remove duplicate TemplateSchema, import from template-storage - Revert contributor-specific .gitignore additions - Fix broken i18n placeholders and missing translations (zh/ja/zh-Hant) - Remove unused setFiles prop from ChatLobby - Remove tags feature (unnecessary complexity) - Improve template card layout: overlay icons on hover, align stats - Add break-all and overflow-hidden for long prompt text in dialogs - Move incrementClickCount into sendTemplate for accurate tracking - Use Intl.RelativeTimeFormat for locale-aware relative time * feat: restore Quick Examples panel and add lobby panel visibility settings Bring back the ExamplePanel as a third collapsible section in ChatLobby alongside Recent Chats and My Templates. Add toggle switches in Settings to show/hide each lobby panel, persisted via localStorage. * fix: template send race condition, import defaults, and empty title bug - Use flushSync instead of setTimeout(0) in handleSendTemplate to ensure React state is flushed before form submission - Explicitly validate and default all fields in importTemplates to prevent undefined counters from malformed import JSON - Fall back to existing title in edit dialog instead of writing undefined * fix: address Copilot review comments and remove PRD file - Fix fallback formatLastUsed returning "Not used yet" for recent usage - Remove dead mounted flag in TemplatePanel useEffect - Respect panel visibility settings in no-history lobby state - Reject empty/whitespace titles in import validation - Trim title/prompt in importTemplates with default title fallback - Remove tasks/prd-template-library-replaces-examples.md from repo * fix: remove double sort, dead code, redundant stats, and break-all CSS - Remove redundant sortTemplates call in loadTemplates (already sorted by getAllTemplates) - Remove unused createEmptyTemplateInput and sortTemplates import - Show "Not used yet" only once for unused templates instead of twice - Use break-words instead of break-all on prompt textareas --------- Co-authored-by: 杜雷 <dreamfly@126.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-04-03 11:16:01 +08:00
} catch (error) {
console.error("Failed to increment run count:", error)
}
}
// Search
export function searchTemplates(
templates: Template[],
query: string,
): Template[] {
if (!query.trim()) return templates
const lowerQuery = query.toLowerCase()
return templates.filter((t) => {
const titleMatch = t.title.toLowerCase().includes(lowerQuery)
const descMatch =
t.description?.toLowerCase().includes(lowerQuery) ?? false
return titleMatch || descMatch
})
}
// Sorting
export function sortTemplates(templates: Template[]): Template[] {
return [...templates].sort((a, b) => {
// pinned desc
if (a.pinned !== b.pinned) return a.pinned ? -1 : 1
// runCount desc
if (a.runCount !== b.runCount) return b.runCount - a.runCount
// lastUsedAt desc
if (a.lastUsedAt !== b.lastUsedAt) return b.lastUsedAt - a.lastUsedAt
// updatedAt desc
return b.updatedAt - a.updatedAt
})
}
// Import / Export
export const TEMPLATE_EXPORT_SCHEMA_VERSION = 1
export interface TemplateExportData {
schemaVersion: number
exportedAt: number
templates: Template[]
}
export function exportTemplates(templates: Template[]): TemplateExportData {
return {
schemaVersion: TEMPLATE_EXPORT_SCHEMA_VERSION,
exportedAt: Date.now(),
templates,
}
}
export function validateImportData(data: unknown): {
valid: boolean
error?: string
} {
if (!data || typeof data !== "object") {
return { valid: false, error: "Invalid data: expected an object" }
}
const obj = data as Record<string, unknown>
if (typeof obj.schemaVersion !== "number") {
return { valid: false, error: "Missing or invalid schemaVersion" }
}
if (!Array.isArray(obj.templates)) {
return { valid: false, error: "Missing or invalid templates array" }
}
for (let i = 0; i < obj.templates.length; i++) {
const t = obj.templates[i]
if (!t || typeof t !== "object") {
return {
valid: false,
error: `Template at index ${i} is not an object`,
}
}
const template = t as Record<string, unknown>
if (typeof template.prompt !== "string" || !template.prompt.trim()) {
return {
valid: false,
error: `Template at index ${i} has missing or empty prompt`,
}
}
if (typeof template.title !== "string" || !template.title.trim()) {
return {
valid: false,
error: `Template at index ${i} has missing or empty title`,
}
}
}
return { valid: true }
}
export async function importTemplates(
templates: Template[],
existingTemplates: Template[],
): Promise<{ imported: number; skipped: number }> {
let imported = 0
let skipped = 0
const existingKeys = new Set(
existingTemplates.map((t) => `${t.title}|||${t.prompt}`),
)
for (const t of templates) {
const key = `${t.title}|||${t.prompt}`
if (existingKeys.has(key)) {
skipped++
continue
}
const now = Date.now()
const newTemplate: Template = {
id: nanoid(),
title:
String(t.title || "").trim() ||
generateDefaultTitle(String(t.prompt || "")),
prompt: String(t.prompt || "").trim(),
description: t.description ? String(t.description) : undefined,
createdAt: typeof t.createdAt === "number" ? t.createdAt : now,
updatedAt: now,
clickCount: typeof t.clickCount === "number" ? t.clickCount : 0,
runCount: typeof t.runCount === "number" ? t.runCount : 0,
lastUsedAt: typeof t.lastUsedAt === "number" ? t.lastUsedAt : 0,
pinned: typeof t.pinned === "boolean" ? t.pinned : false,
}
try {
chore: remove dead code from previous #815 fix attempts (#841) PR #840 fixed issue #815 in the Electron main process via will-prevent-unload + preventDefault. The renderer-side workarounds introduced by previous fix attempts (#642, #648) are no longer needed and never had effect for their stated purpose. Removed: - configuration={ confirmExit: false } in DrawIoEmbed confirmExit is not a recognized draw.io config key (zero matches in jgraph/drawio source). This was always dead code. - modified=0 / keepmodified=0 URL parameters Per drawio source (app.min.js:14898), these only suppress the post-save modified-flag clearing — they do not prevent edits from setting editor.modified=true. They were ineffective for blocking beforeunload prompts and actually prevented draw.io from clearing its modified flag after save. - canPersist / canPersistChecked state and isIndexedDBUsable() probe Their only purpose was gating the dead config above. Removing them also removes a startup delay before the iframe renders. - handleDrawioAutoSave wrapper After PR #780 stripped its body, it was a pure passthrough useCallback. Now passes handleDiagramAutoSave directly to onAutoSave. - withDB / isClosingError / resetDBPromise / onversionchange / onclose / terminated handlers in lib/session-storage.ts and lib/template-storage.ts PR #648 added these to recover from 'IDBDatabase: connection is closing' errors that PR #642's first land caused via db.close() on the shared singleton. That bug was already fixed in c5de1a1 (re-land of #642), three minutes before PR #648 commits started. The retry handlers defend against multi-tab / version-change scenarios that cannot occur in this single-instance Electron app (requestSingleInstanceLock). template-storage.ts copied the same pattern when introduced by #773. Verified: - npx tsc --noEmit passes - Manual test in dev mode: session save/load works, template create works, diagram-only persistence works.
2026-05-21 08:37:14 +09:00
const db = await getDB()
await db.put(STORE_NAME, newTemplate)
feat: add personal My Templates library alongside Quick Examples (#773) * 增加了ralph自动化编程梳理 * feat: US-001 - 为模板库建立独立的 IndexedDB 存储层 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-002 - 在空聊天状态用我的模板库替换官方示例 - 将 ChatLobby 中的 Quick Examples 替换为 TemplatePanel - 当没有历史会话时,展示完整的模板库面板 - 当有历史会话时,展示可折叠的 "My Templates" 区域 - 使用 TemplatePanel 组件展示用户的个人模板库 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-004 - Provide template creation flow - Create TemplateCreateDialog component with form fields for prompt, title, description, tags, and pinned - Add i18n translations for template creation UI in en, zh, zh-Hant, ja - Update TemplatePanel to integrate the create dialog - Support initialPrompt prop for pre-filling from current input - Validate required prompt field (empty prompt not allowed) - Auto-generate default title from first 20 chars of Pin templates appear at top of list Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-005 - 为模板卡片提供编辑、删除和复制操作 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-006 - Send template directly on click and record usage statistics - Implement click-to-send template functionality with confirmation dialog - Add clickCount and runCount increment logic - Display runCount and lastUsedAt on template card - Add i18n translations for confirmation dialog (en, zh, zh-Hant, ja) - Pass onSendTemplate and currentInput props through component hierarchy Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-007 - Support template search, pin and default sorting - Add search bar to TemplatePanel with real-time filtering by title, description, and tags - Add pin/unpin toggle button on template cards (uses Bookmark icon with fill indicator) - Search uses existing searchTemplates function from template-storage - Sort uses existing sortTemplates function (pinned desc, runCount desc, lastUsedAt desc, updatedAt desc) - Show empty state with Search icon when search returns no results - List re-sorts immediately after pin/unpin toggle - Add i18n keys: searchPlaceholder, searchNoResults, pin, unpin for all 4 languages Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-008 - Support saving current input as template Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-009 - Support saving historical user message as template - Add "Save as Template" button to user messages - Pre-fill prompt with original user message text - Only show on user messages,- Dialog opens TemplateCreateDialog on click - Template appears in list immediately after saving Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: US-010 - Support template import and export Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: remove local-only dirs from git tracking (.agents, .cursor, scripts, screenshots) These directories contain local IDE configs, agent scripts, and dev tooling that should not be part of the upstream repository. Added them to .gitignore to prevent future accidental commits. * chore: remove AGENTS.md from git tracking * fix: add missing i18n keys for template export/import (en/zh/zh-Hant/ja) * fix: review fixes for my-templates PR - Fix fragile querySelector("form") with id-based lookup - Add objectStoreNames.contains guards for IndexedDB upgrades - Remove duplicate TemplateSchema, import from template-storage - Revert contributor-specific .gitignore additions - Fix broken i18n placeholders and missing translations (zh/ja/zh-Hant) - Remove unused setFiles prop from ChatLobby - Remove tags feature (unnecessary complexity) - Improve template card layout: overlay icons on hover, align stats - Add break-all and overflow-hidden for long prompt text in dialogs - Move incrementClickCount into sendTemplate for accurate tracking - Use Intl.RelativeTimeFormat for locale-aware relative time * feat: restore Quick Examples panel and add lobby panel visibility settings Bring back the ExamplePanel as a third collapsible section in ChatLobby alongside Recent Chats and My Templates. Add toggle switches in Settings to show/hide each lobby panel, persisted via localStorage. * fix: template send race condition, import defaults, and empty title bug - Use flushSync instead of setTimeout(0) in handleSendTemplate to ensure React state is flushed before form submission - Explicitly validate and default all fields in importTemplates to prevent undefined counters from malformed import JSON - Fall back to existing title in edit dialog instead of writing undefined * fix: address Copilot review comments and remove PRD file - Fix fallback formatLastUsed returning "Not used yet" for recent usage - Remove dead mounted flag in TemplatePanel useEffect - Respect panel visibility settings in no-history lobby state - Reject empty/whitespace titles in import validation - Trim title/prompt in importTemplates with default title fallback - Remove tasks/prd-template-library-replaces-examples.md from repo * fix: remove double sort, dead code, redundant stats, and break-all CSS - Remove redundant sortTemplates call in loadTemplates (already sorted by getAllTemplates) - Remove unused createEmptyTemplateInput and sortTemplates import - Show "Not used yet" only once for unused templates instead of twice - Use break-words instead of break-all on prompt textareas --------- Co-authored-by: 杜雷 <dreamfly@126.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: dayuan.jiang <jdy.toh@gmail.com>
2026-04-03 11:16:01 +08:00
existingKeys.add(key)
imported++
} catch (error) {
console.error("Failed to import template:", error)
}
}
return { imported, skipped }
}