diff --git a/src/components/custom/widget/WorkflowTemplateSelector.vue b/src/components/custom/widget/WorkflowTemplateSelector.vue new file mode 100644 index 000000000..758f40310 --- /dev/null +++ b/src/components/custom/widget/WorkflowTemplateSelector.vue @@ -0,0 +1,355 @@ + + + diff --git a/src/composables/useCoreCommands.ts b/src/composables/useCoreCommands.ts index 80eeca78f..82cd3426d 100644 --- a/src/composables/useCoreCommands.ts +++ b/src/composables/useCoreCommands.ts @@ -246,7 +246,7 @@ export function useCoreCommands(): ComfyCommand[] { icon: 'pi pi-folder-open', label: 'Browse Templates', function: () => { - dialogService.showTemplateWorkflowsDialog() + dialogService.showWorkflowTemplateSelectorDialog() } }, { diff --git a/src/locales/en/main.json b/src/locales/en/main.json index b4c253708..582f6fc76 100644 --- a/src/locales/en/main.json +++ b/src/locales/en/main.json @@ -882,6 +882,21 @@ "audio_ace_step_1_t2a_song": "ACE Step v1 Text to Song", "audio_ace_step_1_m2m_editing": "ACE Step v1 M2M Editing" } + }, + "categories": "Categories", + "resetFilters": "Reset Filters", + "sorting": "Sort by", + "activeFilters": "Filters:", + "loading": "Loading templates...", + "noResults": "No templates found", + "noResultsHint": "Try adjusting your search or filters", + "modelFilter": "Model Filter", + "modelsSelected": "{count} Models", + "resultsCount": "Showing {count} of {total} templates", + "sort": { + "recommended": "Recommended", + "alphabetical": "A → Z", + "newest": "Newest" } }, "graphCanvasMenu": { diff --git a/src/scripts/api.ts b/src/scripts/api.ts index e83eb9f8b..69a9cb1e7 100644 --- a/src/scripts/api.ts +++ b/src/scripts/api.ts @@ -597,11 +597,28 @@ export class ComfyApi extends EventTarget { /** * Gets the index of core workflow templates. + * @param locale Optional locale code (e.g., 'en', 'fr', 'zh') to load localized templates */ - async getCoreWorkflowTemplates(): Promise { - const res = await axios.get(this.fileURL('/templates/index.json')) - const contentType = res.headers['content-type'] - return contentType?.includes('application/json') ? res.data : [] + async getCoreWorkflowTemplates( + locale?: string + ): Promise { + const fileName = + locale && locale !== 'en' ? `index.${locale}.json` : 'index.json' + try { + const res = await axios.get(this.fileURL(`/templates/${fileName}`)) + const contentType = res.headers['content-type'] + return contentType?.includes('application/json') ? res.data : [] + } catch (error) { + // Fallback to default English version if localized version doesn't exist + if (locale && locale !== 'en') { + console.warn( + `Localized templates for '${locale}' not found, falling back to English` + ) + return this.getCoreWorkflowTemplates('en') + } + console.error('Error loading core workflow templates:', error) + return [] + } } /** diff --git a/src/services/dialogService.ts b/src/services/dialogService.ts index 3f0ca9d9a..83d8e6544 100644 --- a/src/services/dialogService.ts +++ b/src/services/dialogService.ts @@ -1,6 +1,7 @@ import { merge } from 'es-toolkit/compat' import { Component } from 'vue' +import WorkflowTemplateSelector from '@/components/custom/widget/WorkflowTemplateSelector.vue' import ApiNodesSignInContent from '@/components/dialog/content/ApiNodesSignInContent.vue' import ConfirmationDialogContent from '@/components/dialog/content/ConfirmationDialogContent.vue' import ErrorDialogContent from '@/components/dialog/content/ErrorDialogContent.vue' @@ -124,6 +125,28 @@ export const useDialogService = () => { }) } + function showWorkflowTemplateSelectorDialog() { + const layoutDefaultProps: DialogComponentProps = { + headless: true, + modal: true, + closable: false, + pt: { + content: { class: '!px-0' }, + root: { style: 'width: 90vw; max-width: 1400px; height: 85vh;' } + } + } + + showLayoutDialog({ + key: 'global-workflow-template-selector', + component: WorkflowTemplateSelector, + props: { + onClose: () => + dialogStore.closeDialog({ key: 'global-workflow-template-selector' }) + }, + dialogComponentProps: layoutDefaultProps + }) + } + function showIssueReportDialog( props: InstanceType['$props'] ) { @@ -470,6 +493,7 @@ export const useDialogService = () => { showAboutDialog, showExecutionErrorDialog, showTemplateWorkflowsDialog, + showWorkflowTemplateSelectorDialog, showIssueReportDialog, showManagerDialog, showManagerProgressDialog,