[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-langgenius-dify-.agents-skills-component-refactoring":3},{"error":4,"detail":5,"metadata":41,"markdownContent":42,"rawMarkdown":38},false,{"repo_full_name":6,"owner":7,"repo_name":8,"repo_forks":9,"skill_path":10,"repo_stars":11,"name":12,"category_id":13,"description":14,"file_tree":15,"skill_md_content":38,"skill_id":39,"skill_key":40},"langgenius/dify","langgenius","dify",20783,".agents/skills/component-refactoring",133463,"component-refactoring",1,"Refactor high-complexity React components in Dify frontend. Use when `pnpm analyze-component --json` shows complexity > 50 or lineCount > 300, when the user asks for code splitting, hook extraction, or complexity reduction, or when `pnpm analyze-component` warns to refactor before testing; avoid for simple/well-structured components, third-party wrappers, or when the user explicitly wants testing without refactoring.",[16,21],{"name":17,"path":18,"size":19,"type":20},"SKILL.md",".agents/skills/component-refactoring/SKILL.md",13619,"file",{"name":22,"path":23,"type":24,"children":25},"references",".agents/skills/component-refactoring/references","folder",[26,30,34],{"name":27,"path":28,"size":29,"type":20},"complexity-patterns.md",".agents/skills/component-refactoring/references/complexity-patterns.md",11890,{"name":31,"path":32,"size":33,"type":20},"component-splitting.md",".agents/skills/component-refactoring/references/component-splitting.md",11677,{"name":35,"path":36,"size":37,"type":20},"hook-extraction.md",".agents/skills/component-refactoring/references/hook-extraction.md",7905,"---\nname: component-refactoring\ndescription: Refactor high-complexity React components in Dify frontend. Use when `pnpm analyze-component --json` shows complexity > 50 or lineCount > 300, when the user asks for code splitting, hook extraction, or complexity reduction, or when `pnpm analyze-component` warns to refactor before testing; avoid for simple/well-structured components, third-party wrappers, or when the user explicitly wants testing without refactoring.\n---\n\n# Dify Component Refactoring Skill\n\nRefactor high-complexity React components in the Dify frontend codebase with the patterns and workflow below.\n\n> **Complexity Threshold**: Components with complexity > 50 (measured by `pnpm analyze-component`) should be refactored before testing.\n\n## Quick Reference\n\n### Commands (run from `web/`)\n\nUse paths relative to `web/` (e.g., `app/components/...`).\nUse `refactor-component` for refactoring prompts and `analyze-component` for testing prompts and metrics.\n\n```bash\ncd web\n\n# Generate refactoring prompt\npnpm refactor-component \u003Cpath>\n\n# Output refactoring analysis as JSON\npnpm refactor-component \u003Cpath> --json\n\n# Generate testing prompt (after refactoring)\npnpm analyze-component \u003Cpath>\n\n# Output testing analysis as JSON\npnpm analyze-component \u003Cpath> --json\n```\n\n### Complexity Analysis\n\n```bash\n# Analyze component complexity\npnpm analyze-component \u003Cpath> --json\n\n# Key metrics to check:\n# - complexity: normalized score 0-100 (target \u003C 50)\n# - maxComplexity: highest single function complexity\n# - lineCount: total lines (target \u003C 300)\n```\n\n### Complexity Score Interpretation\n\n| Score | Level | Action |\n|-------|-------|--------|\n| 0-25 | 🟢 Simple | Ready for testing |\n| 26-50 | 🟡 Medium | Consider minor refactoring |\n| 51-75 | 🟠 Complex | **Refactor before testing** |\n| 76-100 | 🔴 Very Complex | **Must refactor** |\n\n## Core Refactoring Patterns\n\n### Pattern 1: Extract Custom Hooks\n\n**When**: Component has complex state management, multiple `useState`/`useEffect`, or business logic mixed with UI.\n\n**Dify Convention**: Place hooks in a `hooks/` subdirectory or alongside the component as `use-\u003Cfeature>.ts`.\n\n```typescript\n// ❌ Before: Complex state logic in component\nconst Configuration: FC = () => {\n  const [modelConfig, setModelConfig] = useState\u003CModelConfig>(...)\n  const [datasetConfigs, setDatasetConfigs] = useState\u003CDatasetConfigs>(...)\n  const [completionParams, setCompletionParams] = useState\u003CFormValue>({})\n  \n  // 50+ lines of state management logic...\n  \n  return \u003Cdiv>...\u003C/div>\n}\n\n// ✅ After: Extract to custom hook\n// hooks/use-model-config.ts\nexport const useModelConfig = (appId: string) => {\n  const [modelConfig, setModelConfig] = useState\u003CModelConfig>(...)\n  const [completionParams, setCompletionParams] = useState\u003CFormValue>({})\n  \n  // Related state management logic here\n  \n  return { modelConfig, setModelConfig, completionParams, setCompletionParams }\n}\n\n// Component becomes cleaner\nconst Configuration: FC = () => {\n  const { modelConfig, setModelConfig } = useModelConfig(appId)\n  return \u003Cdiv>...\u003C/div>\n}\n```\n\n**Dify Examples**:\n- `web/app/components/app/configuration/hooks/use-advanced-prompt-config.ts`\n- `web/app/components/app/configuration/debug/hooks.tsx`\n- `web/app/components/workflow/hooks/use-workflow.ts`\n\n### Pattern 2: Extract Sub-Components\n\n**When**: Single component has multiple UI sections, conditional rendering blocks, or repeated patterns.\n\n**Dify Convention**: Place sub-components in subdirectories or as separate files in the same directory.\n\n```typescript\n// ❌ Before: Monolithic JSX with multiple sections\nconst AppInfo = () => {\n  return (\n    \u003Cdiv>\n      {/* 100 lines of header UI */}\n      {/* 100 lines of operations UI */}\n      {/* 100 lines of modals */}\n    \u003C/div>\n  )\n}\n\n// ✅ After: Split into focused components\n// app-info/\n//   ├── index.tsx           (orchestration only)\n//   ├── app-header.tsx      (header UI)\n//   ├── app-operations.tsx  (operations UI)\n//   └── app-modals.tsx      (modal management)\n\nconst AppInfo = () => {\n  const { showModal, setShowModal } = useAppInfoModals()\n  \n  return (\n    \u003Cdiv>\n      \u003CAppHeader appDetail={appDetail} />\n      \u003CAppOperations onAction={handleAction} />\n      \u003CAppModals show={showModal} onClose={() => setShowModal(null)} />\n    \u003C/div>\n  )\n}\n```\n\n**Dify Examples**:\n- `web/app/components/app/configuration/` directory structure\n- `web/app/components/workflow/nodes/` per-node organization\n\n### Pattern 3: Simplify Conditional Logic\n\n**When**: Deep nesting (> 3 levels), complex ternaries, or multiple `if/else` chains.\n\n```typescript\n// ❌ Before: Deeply nested conditionals\nconst Template = useMemo(() => {\n  if (appDetail?.mode === AppModeEnum.CHAT) {\n    switch (locale) {\n      case LanguagesSupported[1]:\n        return \u003CTemplateChatZh />\n      case LanguagesSupported[7]:\n        return \u003CTemplateChatJa />\n      default:\n        return \u003CTemplateChatEn />\n    }\n  }\n  if (appDetail?.mode === AppModeEnum.ADVANCED_CHAT) {\n    // Another 15 lines...\n  }\n  // More conditions...\n}, [appDetail, locale])\n\n// ✅ After: Use lookup tables + early returns\nconst TEMPLATE_MAP = {\n  [AppModeEnum.CHAT]: {\n    [LanguagesSupported[1]]: TemplateChatZh,\n    [LanguagesSupported[7]]: TemplateChatJa,\n    default: TemplateChatEn,\n  },\n  [AppModeEnum.ADVANCED_CHAT]: {\n    [LanguagesSupported[1]]: TemplateAdvancedChatZh,\n    // ...\n  },\n}\n\nconst Template = useMemo(() => {\n  const modeTemplates = TEMPLATE_MAP[appDetail?.mode]\n  if (!modeTemplates) return null\n  \n  const TemplateComponent = modeTemplates[locale] || modeTemplates.default\n  return \u003CTemplateComponent appDetail={appDetail} />\n}, [appDetail, locale])\n```\n\n### Pattern 4: Extract API/Data Logic\n\n**When**: Component directly handles API calls, data transformation, or complex async operations.\n\n**Dify Convention**:\n- This skill is for component decomposition, not query/mutation design.\n- When refactoring data fetching, follow `web/AGENTS.md`.\n- Use `frontend-query-mutation` for contracts, query shape, data-fetching wrappers, query/mutation call-site patterns, conditional queries, invalidation, and mutation error handling.\n- Do not introduce deprecated `useInvalid` / `useReset`.\n- Do not add thin passthrough `useQuery` wrappers during refactoring; only extract a custom hook when it truly orchestrates multiple queries/mutations or shared derived state.\n\n**Dify Examples**:\n- `web/service/use-workflow.ts`\n- `web/service/use-common.ts`\n- `web/service/knowledge/use-dataset.ts`\n- `web/service/knowledge/use-document.ts`\n\n### Pattern 5: Extract Modal/Dialog Management\n\n**When**: Component manages multiple modals with complex open/close states.\n\n**Dify Convention**: Modals should be extracted with their state management.\n\n```typescript\n// ❌ Before: Multiple modal states in component\nconst AppInfo = () => {\n  const [showEditModal, setShowEditModal] = useState(false)\n  const [showDuplicateModal, setShowDuplicateModal] = useState(false)\n  const [showConfirmDelete, setShowConfirmDelete] = useState(false)\n  const [showSwitchModal, setShowSwitchModal] = useState(false)\n  const [showImportDSLModal, setShowImportDSLModal] = useState(false)\n  // 5+ more modal states...\n}\n\n// ✅ After: Extract to modal management hook\ntype ModalType = 'edit' | 'duplicate' | 'delete' | 'switch' | 'import' | null\n\nconst useAppInfoModals = () => {\n  const [activeModal, setActiveModal] = useState\u003CModalType>(null)\n  \n  const openModal = useCallback((type: ModalType) => setActiveModal(type), [])\n  const closeModal = useCallback(() => setActiveModal(null), [])\n  \n  return {\n    activeModal,\n    openModal,\n    closeModal,\n    isOpen: (type: ModalType) => activeModal === type,\n  }\n}\n```\n\n### Pattern 6: Extract Form Logic\n\n**When**: Complex form validation, submission handling, or field transformation.\n\n**Dify Convention**: Use `@tanstack/react-form` patterns from `web/app/components/base/form/`.\n\n```typescript\n// ✅ Use existing form infrastructure\nimport { useAppForm } from '@/app/components/base/form'\n\nconst ConfigForm = () => {\n  const form = useAppForm({\n    defaultValues: { name: '', description: '' },\n    onSubmit: handleSubmit,\n  })\n  \n  return \u003Cform.Provider>...\u003C/form.Provider>\n}\n```\n\n## Dify-Specific Refactoring Guidelines\n\n### 1. Context Provider Extraction\n\n**When**: Component provides complex context values with multiple states.\n\n```typescript\n// ❌ Before: Large context value object\nconst value = {\n  appId, isAPIKeySet, isTrailFinished, mode, modelModeType,\n  promptMode, isAdvancedMode, isAgent, isOpenAI, isFunctionCall,\n  // 50+ more properties...\n}\nreturn \u003CConfigContext.Provider value={value}>...\u003C/ConfigContext.Provider>\n\n// ✅ After: Split into domain-specific contexts\n\u003CModelConfigProvider value={modelConfigValue}>\n  \u003CDatasetConfigProvider value={datasetConfigValue}>\n    \u003CUIConfigProvider value={uiConfigValue}>\n      {children}\n    \u003C/UIConfigProvider>\n  \u003C/DatasetConfigProvider>\n\u003C/ModelConfigProvider>\n```\n\n**Dify Reference**: `web/context/` directory structure\n\n### 2. Workflow Node Components\n\n**When**: Refactoring workflow node components (`web/app/components/workflow/nodes/`).\n\n**Conventions**:\n- Keep node logic in `use-interactions.ts`\n- Extract panel UI to separate files\n- Use `_base` components for common patterns\n\n```\nnodes/\u003Cnode-type>/\n  ├── index.tsx              # Node registration\n  ├── node.tsx               # Node visual component\n  ├── panel.tsx              # Configuration panel\n  ├── use-interactions.ts    # Node-specific hooks\n  └── types.ts               # Type definitions\n```\n\n### 3. Configuration Components\n\n**When**: Refactoring app configuration components.\n\n**Conventions**:\n- Separate config sections into subdirectories\n- Use existing patterns from `web/app/components/app/configuration/`\n- Keep feature toggles in dedicated components\n\n### 4. Tool/Plugin Components\n\n**When**: Refactoring tool-related components (`web/app/components/tools/`).\n\n**Conventions**:\n- Follow existing modal patterns\n- Use service hooks from `web/service/use-tools.ts`\n- Keep provider-specific logic isolated\n\n## Refactoring Workflow\n\n### Step 1: Generate Refactoring Prompt\n\n```bash\npnpm refactor-component \u003Cpath>\n```\n\nThis command will:\n- Analyze component complexity and features\n- Identify specific refactoring actions needed\n- Generate a prompt for AI assistant (auto-copied to clipboard on macOS)\n- Provide detailed requirements based on detected patterns\n\n### Step 2: Analyze Details\n\n```bash\npnpm analyze-component \u003Cpath> --json\n```\n\nIdentify:\n- Total complexity score\n- Max function complexity\n- Line count\n- Features detected (state, effects, API, etc.)\n\n### Step 3: Plan\n\nCreate a refactoring plan based on detected features:\n\n| Detected Feature | Refactoring Action |\n|------------------|-------------------|\n| `hasState: true` + `hasEffects: true` | Extract custom hook |\n| `hasAPI: true` | Extract data/service hook |\n| `hasEvents: true` (many) | Extract event handlers |\n| `lineCount > 300` | Split into sub-components |\n| `maxComplexity > 50` | Simplify conditional logic |\n\n### Step 4: Execute Incrementally\n\n1. **Extract one piece at a time**\n2. **Run lint, type-check, and tests after each extraction**\n3. **Verify functionality before next step**\n\n```\nFor each extraction:\n  ┌────────────────────────────────────────┐\n  │ 1. Extract code                        │\n  │ 2. Run: pnpm lint:fix                  │\n  │ 3. Run: pnpm type-check:tsgo           │\n  │ 4. Run: pnpm test                      │\n  │ 5. Test functionality manually         │\n  │ 6. PASS? → Next extraction             │\n  │    FAIL? → Fix before continuing       │\n  └────────────────────────────────────────┘\n```\n\n### Step 5: Verify\n\nAfter refactoring:\n\n```bash\n# Re-run refactor command to verify improvements\npnpm refactor-component \u003Cpath>\n\n# If complexity \u003C 25 and lines \u003C 200, you'll see:\n# ✅ COMPONENT IS WELL-STRUCTURED\n\n# For detailed metrics:\npnpm analyze-component \u003Cpath> --json\n\n# Target metrics:\n# - complexity \u003C 50\n# - lineCount \u003C 300\n# - maxComplexity \u003C 30\n```\n\n## Common Mistakes to Avoid\n\n### ❌ Over-Engineering\n\n```typescript\n// ❌ Too many tiny hooks\nconst useButtonText = () => useState('Click')\nconst useButtonDisabled = () => useState(false)\nconst useButtonLoading = () => useState(false)\n\n// ✅ Cohesive hook with related state\nconst useButtonState = () => {\n  const [text, setText] = useState('Click')\n  const [disabled, setDisabled] = useState(false)\n  const [loading, setLoading] = useState(false)\n  return { text, setText, disabled, setDisabled, loading, setLoading }\n}\n```\n\n### ❌ Breaking Existing Patterns\n\n- Follow existing directory structures\n- Maintain naming conventions\n- Preserve export patterns for compatibility\n\n### ❌ Premature Abstraction\n\n- Only extract when there's clear complexity benefit\n- Don't create abstractions for single-use code\n- Keep refactored code in the same domain area\n\n## References\n\n### Dify Codebase Examples\n\n- **Hook extraction**: `web/app/components/app/configuration/hooks/`\n- **Component splitting**: `web/app/components/app/configuration/`\n- **Service hooks**: `web/service/use-*.ts`\n- **Workflow patterns**: `web/app/components/workflow/hooks/`\n- **Form patterns**: `web/app/components/base/form/`\n\n### Related Skills\n\n- `frontend-testing` - For testing refactored components\n- `web/docs/test.md` - Testing specification\n","35f84107-0af1-5646-8a81-a17c478c7df5","langgenius-dify-.agents-skills-component-refactoring",{"name":12,"description":14},"\u003Ch1>Dify Component Refactoring Skill\u003C/h1>\n\u003Cp>Refactor high-complexity React components in the Dify frontend codebase with the patterns and workflow below.\u003C/p>\n\u003Cblockquote>\n\u003Cp>\u003Cstrong>Complexity Threshold\u003C/strong>: Components with complexity &gt; 50 (measured by \u003Ccode>pnpm analyze-component\u003C/code>) should be refactored before testing.\u003C/p>\n\u003C/blockquote>\n\u003Ch2>Quick Reference\u003C/h2>\n\u003Ch3>Commands (run from \u003Ccode>web/\u003C/code>)\u003C/h3>\n\u003Cp>Use paths relative to \u003Ccode>web/\u003C/code> (e.g., \u003Ccode>app/components/...\u003C/code>).\nUse \u003Ccode>refactor-component\u003C/code> for refactoring prompts and \u003Ccode>analyze-component\u003C/code> for testing prompts and metrics.\u003C/p>\n\u003Cdiv class=\"md-code-block\">\u003Cdiv class=\"md-code-lang\">bash\u003C/div>\u003Cpre>\u003Ccode class=\"hljs language-bash\">\u003Cspan class=\"hljs-built_in\">cd\u003C/span> web\n\n\u003Cspan class=\"hljs-comment\"># Generate refactoring prompt\u003C/span>\npnpm refactor-component &lt;path&gt;\n\n\u003Cspan class=\"hljs-comment\"># Output refactoring analysis as JSON\u003C/span>\npnpm refactor-component &lt;path&gt; --json\n\n\u003Cspan class=\"hljs-comment\"># Generate testing prompt (after refactoring)\u003C/span>\npnpm analyze-component &lt;path&gt;\n\n\u003Cspan class=\"hljs-comment\"># Output testing analysis as JSON\u003C/span>\npnpm analyze-component &lt;path&gt; --json\u003C/code>\u003C/pre>\u003C/div>\u003Ch3>Complexity Analysis\u003C/h3>\n\u003Cdiv class=\"md-code-block\">\u003Cdiv class=\"md-code-lang\">bash\u003C/div>\u003Cpre>\u003Ccode class=\"hljs language-bash\">\u003Cspan class=\"hljs-comment\"># Analyze component complexity\u003C/span>\npnpm analyze-component &lt;path&gt; --json\n\n\u003Cspan class=\"hljs-comment\"># Key metrics to check:\u003C/span>\n\u003Cspan class=\"hljs-comment\"># - complexity: normalized score 0-100 (target &lt; 50)\u003C/span>\n\u003Cspan class=\"hljs-comment\"># - maxComplexity: highest single function complexity\u003C/span>\n\u003Cspan class=\"hljs-comment\"># - lineCount: total lines (target &lt; 300)\u003C/span>\u003C/code>\u003C/pre>\u003C/div>\u003Ch3>Complexity Score Interpretation\u003C/h3>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Score\u003C/th>\n\u003Cth>Level\u003C/th>\n\u003Cth>Action\u003C/th>\n\u003C/tr>\n\u003C/thead>\n\u003Ctbody>\u003Ctr>\n\u003Ctd>0-25\u003C/td>\n\u003Ctd>🟢 Simple\u003C/td>\n\u003Ctd>Ready for testing\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>26-50\u003C/td>\n\u003Ctd>🟡 Medium\u003C/td>\n\u003Ctd>Consider minor refactoring\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>51-75\u003C/td>\n\u003Ctd>🟠 Complex\u003C/td>\n\u003Ctd>\u003Cstrong>Refactor before testing\u003C/strong>\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>76-100\u003C/td>\n\u003Ctd>🔴 Very Complex\u003C/td>\n\u003Ctd>\u003Cstrong>Must refactor\u003C/strong>\u003C/td>\n\u003C/tr>\n\u003C/tbody>\u003C/table>\n\u003Ch2>Core Refactoring Patterns\u003C/h2>\n\u003Ch3>Pattern 1: Extract Custom Hooks\u003C/h3>\n\u003Cp>\u003Cstrong>When\u003C/strong>: Component has complex state management, multiple \u003Ccode>useState\u003C/code>/\u003Ccode>useEffect\u003C/code>, or business logic mixed with UI.\u003C/p>\n\u003Cp>\u003Cstrong>Dify Convention\u003C/strong>: Place hooks in a \u003Ccode>hooks/\u003C/code> subdirectory or alongside the component as \u003Ccode>use-&lt;feature&gt;.ts\u003C/code>.\u003C/p>\n\u003Cdiv class=\"md-code-block\">\u003Cdiv class=\"md-code-lang\">typescript\u003C/div>\u003Cpre>\u003Ccode class=\"hljs language-typescript\">\u003Cspan class=\"hljs-comment\">// ❌ Before: Complex state logic in component\u003C/span>\n\u003Cspan class=\"hljs-keyword\">const\u003C/span> \u003Cspan class=\"hljs-title class_\">Configuration\u003C/span>: \u003Cspan class=\"hljs-variable constant_\">FC\u003C/span> = \u003Cspan class=\"hljs-function\">() =&gt;\u003C/span> {\n  \u003Cspan class=\"hljs-keyword\">const\u003C/span> [modelConfig, setModelConfig] = useState&lt;\u003Cspan class=\"hljs-title class_\">ModelConfig\u003C/span>&gt;(...)\n  \u003Cspan class=\"hljs-keyword\">const\u003C/span> [datasetConfigs, setDatasetConfigs] = useState&lt;\u003Cspan class=\"hljs-title class_\">DatasetConfigs\u003C/span>&gt;(...)\n  \u003Cspan class=\"hljs-keyword\">const\u003C/span> [completionParams, setCompletionParams] = useState&lt;\u003Cspan class=\"hljs-title class_\">FormValue\u003C/span>&gt;({})\n  \n  \u003Cspan class=\"hljs-comment\">// 50+ lines of state management logic...\u003C/span>\n  \n  \u003Cspan class=\"hljs-keyword\">return\u003C/span> \u003Cspan class=\"language-xml\">\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">div\u003C/span>&gt;\u003C/span>...\u003Cspan class=\"hljs-tag\">&lt;/\u003Cspan class=\"hljs-name\">div\u003C/span>&gt;\u003C/span>\u003C/span>\n}\n\n\u003Cspan class=\"hljs-comment\">// ✅ After: Extract to custom hook\u003C/span>\n\u003Cspan class=\"hljs-comment\">// hooks/use-model-config.ts\u003C/span>\n\u003Cspan class=\"hljs-keyword\">export\u003C/span> \u003Cspan class=\"hljs-keyword\">const\u003C/span> \u003Cspan class=\"hljs-title function_\">useModelConfig\u003C/span> = (\u003Cspan class=\"hljs-params\">\u003Cspan class=\"hljs-attr\">appId\u003C/span>: \u003Cspan class=\"hljs-built_in\">string\u003C/span>\u003C/span>) =&gt; {\n  \u003Cspan class=\"hljs-keyword\">const\u003C/span> [modelConfig, setModelConfig] = useState&lt;\u003Cspan class=\"hljs-title class_\">ModelConfig\u003C/span>&gt;(...)\n  \u003Cspan class=\"hljs-keyword\">const\u003C/span> [completionParams, setCompletionParams] = useState&lt;\u003Cspan class=\"hljs-title class_\">FormValue\u003C/span>&gt;({})\n  \n  \u003Cspan class=\"hljs-comment\">// Related state management logic here\u003C/span>\n  \n  \u003Cspan class=\"hljs-keyword\">return\u003C/span> { modelConfig, setModelConfig, completionParams, setCompletionParams }\n}\n\n\u003Cspan class=\"hljs-comment\">// Component becomes cleaner\u003C/span>\n\u003Cspan class=\"hljs-keyword\">const\u003C/span> \u003Cspan class=\"hljs-title class_\">Configuration\u003C/span>: \u003Cspan class=\"hljs-variable constant_\">FC\u003C/span> = \u003Cspan class=\"hljs-function\">() =&gt;\u003C/span> {\n  \u003Cspan class=\"hljs-keyword\">const\u003C/span> { modelConfig, setModelConfig } = \u003Cspan class=\"hljs-title function_\">useModelConfig\u003C/span>(appId)\n  \u003Cspan class=\"hljs-keyword\">return\u003C/span> \u003Cspan class=\"language-xml\">\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">div\u003C/span>&gt;\u003C/span>...\u003Cspan class=\"hljs-tag\">&lt;/\u003Cspan class=\"hljs-name\">div\u003C/span>&gt;\u003C/span>\u003C/span>\n}\u003C/code>\u003C/pre>\u003C/div>\u003Cp>\u003Cstrong>Dify Examples\u003C/strong>:\u003C/p>\n\u003Cul>\n\u003Cli>\u003Ccode>web/app/components/app/configuration/hooks/use-advanced-prompt-config.ts\u003C/code>\u003C/li>\n\u003Cli>\u003Ccode>web/app/components/app/configuration/debug/hooks.tsx\u003C/code>\u003C/li>\n\u003Cli>\u003Ccode>web/app/components/workflow/hooks/use-workflow.ts\u003C/code>\u003C/li>\n\u003C/ul>\n\u003Ch3>Pattern 2: Extract Sub-Components\u003C/h3>\n\u003Cp>\u003Cstrong>When\u003C/strong>: Single component has multiple UI sections, conditional rendering blocks, or repeated patterns.\u003C/p>\n\u003Cp>\u003Cstrong>Dify Convention\u003C/strong>: Place sub-components in subdirectories or as separate files in the same directory.\u003C/p>\n\u003Cdiv class=\"md-code-block\">\u003Cdiv class=\"md-code-lang\">typescript\u003C/div>\u003Cpre>\u003Ccode class=\"hljs language-typescript\">\u003Cspan class=\"hljs-comment\">// ❌ Before: Monolithic JSX with multiple sections\u003C/span>\n\u003Cspan class=\"hljs-keyword\">const\u003C/span> \u003Cspan class=\"hljs-title function_\">AppInfo\u003C/span> = (\u003Cspan class=\"hljs-params\">\u003C/span>) =&gt; {\n  \u003Cspan class=\"hljs-keyword\">return\u003C/span> (\n    \u003Cspan class=\"language-xml\">\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">div\u003C/span>&gt;\u003C/span>\n      {/* 100 lines of header UI */}\n      {/* 100 lines of operations UI */}\n      {/* 100 lines of modals */}\n    \u003Cspan class=\"hljs-tag\">&lt;/\u003Cspan class=\"hljs-name\">div\u003C/span>&gt;\u003C/span>\u003C/span>\n  )\n}\n\n\u003Cspan class=\"hljs-comment\">// ✅ After: Split into focused components\u003C/span>\n\u003Cspan class=\"hljs-comment\">// app-info/\u003C/span>\n\u003Cspan class=\"hljs-comment\">//   ├── index.tsx           (orchestration only)\u003C/span>\n\u003Cspan class=\"hljs-comment\">//   ├── app-header.tsx      (header UI)\u003C/span>\n\u003Cspan class=\"hljs-comment\">//   ├── app-operations.tsx  (operations UI)\u003C/span>\n\u003Cspan class=\"hljs-comment\">//   └── app-modals.tsx      (modal management)\u003C/span>\n\n\u003Cspan class=\"hljs-keyword\">const\u003C/span> \u003Cspan class=\"hljs-title function_\">AppInfo\u003C/span> = (\u003Cspan class=\"hljs-params\">\u003C/span>) =&gt; {\n  \u003Cspan class=\"hljs-keyword\">const\u003C/span> { showModal, setShowModal } = \u003Cspan class=\"hljs-title function_\">useAppInfoModals\u003C/span>()\n  \n  \u003Cspan class=\"hljs-keyword\">return\u003C/span> (\n    \u003Cspan class=\"language-xml\">\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">div\u003C/span>&gt;\u003C/span>\n      \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">AppHeader\u003C/span> \u003Cspan class=\"hljs-attr\">appDetail\u003C/span>=\u003Cspan class=\"hljs-string\">{appDetail}\u003C/span> /&gt;\u003C/span>\n      \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">AppOperations\u003C/span> \u003Cspan class=\"hljs-attr\">onAction\u003C/span>=\u003Cspan class=\"hljs-string\">{handleAction}\u003C/span> /&gt;\u003C/span>\n      \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">AppModals\u003C/span> \u003Cspan class=\"hljs-attr\">show\u003C/span>=\u003Cspan class=\"hljs-string\">{showModal}\u003C/span> \u003Cspan class=\"hljs-attr\">onClose\u003C/span>=\u003Cspan class=\"hljs-string\">{()\u003C/span> =&gt;\u003C/span> setShowModal(null)} /&gt;\n    \u003Cspan class=\"hljs-tag\">&lt;/\u003Cspan class=\"hljs-name\">div\u003C/span>&gt;\u003C/span>\u003C/span>\n  )\n}\u003C/code>\u003C/pre>\u003C/div>\u003Cp>\u003Cstrong>Dify Examples\u003C/strong>:\u003C/p>\n\u003Cul>\n\u003Cli>\u003Ccode>web/app/components/app/configuration/\u003C/code> directory structure\u003C/li>\n\u003Cli>\u003Ccode>web/app/components/workflow/nodes/\u003C/code> per-node organization\u003C/li>\n\u003C/ul>\n\u003Ch3>Pattern 3: Simplify Conditional Logic\u003C/h3>\n\u003Cp>\u003Cstrong>When\u003C/strong>: Deep nesting (&gt; 3 levels), complex ternaries, or multiple \u003Ccode>if/else\u003C/code> chains.\u003C/p>\n\u003Cdiv class=\"md-code-block\">\u003Cdiv class=\"md-code-lang\">typescript\u003C/div>\u003Cpre>\u003Ccode class=\"hljs language-typescript\">\u003Cspan class=\"hljs-comment\">// ❌ Before: Deeply nested conditionals\u003C/span>\n\u003Cspan class=\"hljs-keyword\">const\u003C/span> \u003Cspan class=\"hljs-title class_\">Template\u003C/span> = \u003Cspan class=\"hljs-title function_\">useMemo\u003C/span>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C/span> {\n  \u003Cspan class=\"hljs-keyword\">if\u003C/span> (appDetail?.\u003Cspan class=\"hljs-property\">mode\u003C/span> === \u003Cspan class=\"hljs-title class_\">AppModeEnum\u003C/span>.\u003Cspan class=\"hljs-property\">CHAT\u003C/span>) {\n    \u003Cspan class=\"hljs-keyword\">switch\u003C/span> (locale) {\n      \u003Cspan class=\"hljs-keyword\">case\u003C/span> \u003Cspan class=\"hljs-title class_\">LanguagesSupported\u003C/span>[\u003Cspan class=\"hljs-number\">1\u003C/span>]:\n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> \u003Cspan class=\"language-xml\">\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">TemplateChatZh\u003C/span> /&gt;\u003C/span>\u003C/span>\n      \u003Cspan class=\"hljs-keyword\">case\u003C/span> \u003Cspan class=\"hljs-title class_\">LanguagesSupported\u003C/span>[\u003Cspan class=\"hljs-number\">7\u003C/span>]:\n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> \u003Cspan class=\"language-xml\">\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">TemplateChatJa\u003C/span> /&gt;\u003C/span>\u003C/span>\n      \u003Cspan class=\"hljs-attr\">default\u003C/span>:\n        \u003Cspan class=\"hljs-keyword\">return\u003C/span> \u003Cspan class=\"language-xml\">\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">TemplateChatEn\u003C/span> /&gt;\u003C/span>\u003C/span>\n    }\n  }\n  \u003Cspan class=\"hljs-keyword\">if\u003C/span> (appDetail?.\u003Cspan class=\"hljs-property\">mode\u003C/span> === \u003Cspan class=\"hljs-title class_\">AppModeEnum\u003C/span>.\u003Cspan class=\"hljs-property\">ADVANCED_CHAT\u003C/span>) {\n    \u003Cspan class=\"hljs-comment\">// Another 15 lines...\u003C/span>\n  }\n  \u003Cspan class=\"hljs-comment\">// More conditions...\u003C/span>\n}, [appDetail, locale])\n\n\u003Cspan class=\"hljs-comment\">// ✅ After: Use lookup tables + early returns\u003C/span>\n\u003Cspan class=\"hljs-keyword\">const\u003C/span> \u003Cspan class=\"hljs-variable constant_\">TEMPLATE_MAP\u003C/span> = {\n  [\u003Cspan class=\"hljs-title class_\">AppModeEnum\u003C/span>.\u003Cspan class=\"hljs-property\">CHAT\u003C/span>]: {\n    [\u003Cspan class=\"hljs-title class_\">LanguagesSupported\u003C/span>[\u003Cspan class=\"hljs-number\">1\u003C/span>]]: \u003Cspan class=\"hljs-title class_\">TemplateChatZh\u003C/span>,\n    [\u003Cspan class=\"hljs-title class_\">LanguagesSupported\u003C/span>[\u003Cspan class=\"hljs-number\">7\u003C/span>]]: \u003Cspan class=\"hljs-title class_\">TemplateChatJa\u003C/span>,\n    \u003Cspan class=\"hljs-attr\">default\u003C/span>: \u003Cspan class=\"hljs-title class_\">TemplateChatEn\u003C/span>,\n  },\n  [\u003Cspan class=\"hljs-title class_\">AppModeEnum\u003C/span>.\u003Cspan class=\"hljs-property\">ADVANCED_CHAT\u003C/span>]: {\n    [\u003Cspan class=\"hljs-title class_\">LanguagesSupported\u003C/span>[\u003Cspan class=\"hljs-number\">1\u003C/span>]]: \u003Cspan class=\"hljs-title class_\">TemplateAdvancedChatZh\u003C/span>,\n    \u003Cspan class=\"hljs-comment\">// ...\u003C/span>\n  },\n}\n\n\u003Cspan class=\"hljs-keyword\">const\u003C/span> \u003Cspan class=\"hljs-title class_\">Template\u003C/span> = \u003Cspan class=\"hljs-title function_\">useMemo\u003C/span>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C/span> {\n  \u003Cspan class=\"hljs-keyword\">const\u003C/span> modeTemplates = \u003Cspan class=\"hljs-variable constant_\">TEMPLATE_MAP\u003C/span>[appDetail?.\u003Cspan class=\"hljs-property\">mode\u003C/span>]\n  \u003Cspan class=\"hljs-keyword\">if\u003C/span> (!modeTemplates) \u003Cspan class=\"hljs-keyword\">return\u003C/span> \u003Cspan class=\"hljs-literal\">null\u003C/span>\n  \n  \u003Cspan class=\"hljs-keyword\">const\u003C/span> \u003Cspan class=\"hljs-title class_\">TemplateComponent\u003C/span> = modeTemplates[locale] || modeTemplates.\u003Cspan class=\"hljs-property\">default\u003C/span>\n  \u003Cspan class=\"hljs-keyword\">return\u003C/span> \u003Cspan class=\"language-xml\">\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">TemplateComponent\u003C/span> \u003Cspan class=\"hljs-attr\">appDetail\u003C/span>=\u003Cspan class=\"hljs-string\">{appDetail}\u003C/span> /&gt;\u003C/span>\u003C/span>\n}, [appDetail, locale])\u003C/code>\u003C/pre>\u003C/div>\u003Ch3>Pattern 4: Extract API/Data Logic\u003C/h3>\n\u003Cp>\u003Cstrong>When\u003C/strong>: Component directly handles API calls, data transformation, or complex async operations.\u003C/p>\n\u003Cp>\u003Cstrong>Dify Convention\u003C/strong>:\u003C/p>\n\u003Cul>\n\u003Cli>This skill is for component decomposition, not query/mutation design.\u003C/li>\n\u003Cli>When refactoring data fetching, follow \u003Ccode>web/AGENTS.md\u003C/code>.\u003C/li>\n\u003Cli>Use \u003Ccode>frontend-query-mutation\u003C/code> for contracts, query shape, data-fetching wrappers, query/mutation call-site patterns, conditional queries, invalidation, and mutation error handling.\u003C/li>\n\u003Cli>Do not introduce deprecated \u003Ccode>useInvalid\u003C/code> / \u003Ccode>useReset\u003C/code>.\u003C/li>\n\u003Cli>Do not add thin passthrough \u003Ccode>useQuery\u003C/code> wrappers during refactoring; only extract a custom hook when it truly orchestrates multiple queries/mutations or shared derived state.\u003C/li>\n\u003C/ul>\n\u003Cp>\u003Cstrong>Dify Examples\u003C/strong>:\u003C/p>\n\u003Cul>\n\u003Cli>\u003Ccode>web/service/use-workflow.ts\u003C/code>\u003C/li>\n\u003Cli>\u003Ccode>web/service/use-common.ts\u003C/code>\u003C/li>\n\u003Cli>\u003Ccode>web/service/knowledge/use-dataset.ts\u003C/code>\u003C/li>\n\u003Cli>\u003Ccode>web/service/knowledge/use-document.ts\u003C/code>\u003C/li>\n\u003C/ul>\n\u003Ch3>Pattern 5: Extract Modal/Dialog Management\u003C/h3>\n\u003Cp>\u003Cstrong>When\u003C/strong>: Component manages multiple modals with complex open/close states.\u003C/p>\n\u003Cp>\u003Cstrong>Dify Convention\u003C/strong>: Modals should be extracted with their state management.\u003C/p>\n\u003Cdiv class=\"md-code-block\">\u003Cdiv class=\"md-code-lang\">typescript\u003C/div>\u003Cpre>\u003Ccode class=\"hljs language-typescript\">\u003Cspan class=\"hljs-comment\">// ❌ Before: Multiple modal states in component\u003C/span>\n\u003Cspan class=\"hljs-keyword\">const\u003C/span> \u003Cspan class=\"hljs-title function_\">AppInfo\u003C/span> = (\u003Cspan class=\"hljs-params\">\u003C/span>) =&gt; {\n  \u003Cspan class=\"hljs-keyword\">const\u003C/span> [showEditModal, setShowEditModal] = \u003Cspan class=\"hljs-title function_\">useState\u003C/span>(\u003Cspan class=\"hljs-literal\">false\u003C/span>)\n  \u003Cspan class=\"hljs-keyword\">const\u003C/span> [showDuplicateModal, setShowDuplicateModal] = \u003Cspan class=\"hljs-title function_\">useState\u003C/span>(\u003Cspan class=\"hljs-literal\">false\u003C/span>)\n  \u003Cspan class=\"hljs-keyword\">const\u003C/span> [showConfirmDelete, setShowConfirmDelete] = \u003Cspan class=\"hljs-title function_\">useState\u003C/span>(\u003Cspan class=\"hljs-literal\">false\u003C/span>)\n  \u003Cspan class=\"hljs-keyword\">const\u003C/span> [showSwitchModal, setShowSwitchModal] = \u003Cspan class=\"hljs-title function_\">useState\u003C/span>(\u003Cspan class=\"hljs-literal\">false\u003C/span>)\n  \u003Cspan class=\"hljs-keyword\">const\u003C/span> [showImportDSLModal, setShowImportDSLModal] = \u003Cspan class=\"hljs-title function_\">useState\u003C/span>(\u003Cspan class=\"hljs-literal\">false\u003C/span>)\n  \u003Cspan class=\"hljs-comment\">// 5+ more modal states...\u003C/span>\n}\n\n\u003Cspan class=\"hljs-comment\">// ✅ After: Extract to modal management hook\u003C/span>\n\u003Cspan class=\"hljs-keyword\">type\u003C/span> \u003Cspan class=\"hljs-title class_\">ModalType\u003C/span> = \u003Cspan class=\"hljs-string\">&#x27;edit&#x27;\u003C/span> | \u003Cspan class=\"hljs-string\">&#x27;duplicate&#x27;\u003C/span> | \u003Cspan class=\"hljs-string\">&#x27;delete&#x27;\u003C/span> | \u003Cspan class=\"hljs-string\">&#x27;switch&#x27;\u003C/span> | \u003Cspan class=\"hljs-string\">&#x27;import&#x27;\u003C/span> | \u003Cspan class=\"hljs-literal\">null\u003C/span>\n\n\u003Cspan class=\"hljs-keyword\">const\u003C/span> \u003Cspan class=\"hljs-title function_\">useAppInfoModals\u003C/span> = (\u003Cspan class=\"hljs-params\">\u003C/span>) =&gt; {\n  \u003Cspan class=\"hljs-keyword\">const\u003C/span> [activeModal, setActiveModal] = useState&lt;\u003Cspan class=\"hljs-title class_\">ModalType\u003C/span>&gt;(\u003Cspan class=\"hljs-literal\">null\u003C/span>)\n  \n  \u003Cspan class=\"hljs-keyword\">const\u003C/span> openModal = \u003Cspan class=\"hljs-title function_\">useCallback\u003C/span>(\u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">\u003Cspan class=\"hljs-attr\">type\u003C/span>: \u003Cspan class=\"hljs-title class_\">ModalType\u003C/span>\u003C/span>) =&gt;\u003C/span> \u003Cspan class=\"hljs-title function_\">setActiveModal\u003C/span>(\u003Cspan class=\"hljs-keyword\">type\u003C/span>), [])\n  \u003Cspan class=\"hljs-keyword\">const\u003C/span> closeModal = \u003Cspan class=\"hljs-title function_\">useCallback\u003C/span>(\u003Cspan class=\"hljs-function\">() =&gt;\u003C/span> \u003Cspan class=\"hljs-title function_\">setActiveModal\u003C/span>(\u003Cspan class=\"hljs-literal\">null\u003C/span>), [])\n  \n  \u003Cspan class=\"hljs-keyword\">return\u003C/span> {\n    activeModal,\n    openModal,\n    closeModal,\n    \u003Cspan class=\"hljs-attr\">isOpen\u003C/span>: \u003Cspan class=\"hljs-function\">(\u003Cspan class=\"hljs-params\">\u003Cspan class=\"hljs-attr\">type\u003C/span>: \u003Cspan class=\"hljs-title class_\">ModalType\u003C/span>\u003C/span>) =&gt;\u003C/span> activeModal === \u003Cspan class=\"hljs-keyword\">type\u003C/span>,\n  }\n}\u003C/code>\u003C/pre>\u003C/div>\u003Ch3>Pattern 6: Extract Form Logic\u003C/h3>\n\u003Cp>\u003Cstrong>When\u003C/strong>: Complex form validation, submission handling, or field transformation.\u003C/p>\n\u003Cp>\u003Cstrong>Dify Convention\u003C/strong>: Use \u003Ccode>@tanstack/react-form\u003C/code> patterns from \u003Ccode>web/app/components/base/form/\u003C/code>.\u003C/p>\n\u003Cdiv class=\"md-code-block\">\u003Cdiv class=\"md-code-lang\">typescript\u003C/div>\u003Cpre>\u003Ccode class=\"hljs language-typescript\">\u003Cspan class=\"hljs-comment\">// ✅ Use existing form infrastructure\u003C/span>\n\u003Cspan class=\"hljs-keyword\">import\u003C/span> { useAppForm } \u003Cspan class=\"hljs-keyword\">from\u003C/span> \u003Cspan class=\"hljs-string\">&#x27;@/app/components/base/form&#x27;\u003C/span>\n\n\u003Cspan class=\"hljs-keyword\">const\u003C/span> \u003Cspan class=\"hljs-title function_\">ConfigForm\u003C/span> = (\u003Cspan class=\"hljs-params\">\u003C/span>) =&gt; {\n  \u003Cspan class=\"hljs-keyword\">const\u003C/span> form = \u003Cspan class=\"hljs-title function_\">useAppForm\u003C/span>({\n    \u003Cspan class=\"hljs-attr\">defaultValues\u003C/span>: { \u003Cspan class=\"hljs-attr\">name\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C/span>, \u003Cspan class=\"hljs-attr\">description\u003C/span>: \u003Cspan class=\"hljs-string\">&#x27;&#x27;\u003C/span> },\n    \u003Cspan class=\"hljs-attr\">onSubmit\u003C/span>: handleSubmit,\n  })\n  \n  \u003Cspan class=\"hljs-keyword\">return\u003C/span> \u003Cspan class=\"language-xml\">\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">form.Provider\u003C/span>&gt;\u003C/span>...\u003Cspan class=\"hljs-tag\">&lt;/\u003Cspan class=\"hljs-name\">form.Provider\u003C/span>&gt;\u003C/span>\u003C/span>\n}\u003C/code>\u003C/pre>\u003C/div>\u003Ch2>Dify-Specific Refactoring Guidelines\u003C/h2>\n\u003Ch3>1. Context Provider Extraction\u003C/h3>\n\u003Cp>\u003Cstrong>When\u003C/strong>: Component provides complex context values with multiple states.\u003C/p>\n\u003Cdiv class=\"md-code-block\">\u003Cdiv class=\"md-code-lang\">typescript\u003C/div>\u003Cpre>\u003Ccode class=\"hljs language-typescript\">\u003Cspan class=\"hljs-comment\">// ❌ Before: Large context value object\u003C/span>\n\u003Cspan class=\"hljs-keyword\">const\u003C/span> value = {\n  appId, isAPIKeySet, isTrailFinished, mode, modelModeType,\n  promptMode, isAdvancedMode, isAgent, isOpenAI, isFunctionCall,\n  \u003Cspan class=\"hljs-comment\">// 50+ more properties...\u003C/span>\n}\n\u003Cspan class=\"hljs-keyword\">return\u003C/span> \u003Cspan class=\"language-xml\">\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">ConfigContext.Provider\u003C/span> \u003Cspan class=\"hljs-attr\">value\u003C/span>=\u003Cspan class=\"hljs-string\">{value}\u003C/span>&gt;\u003C/span>...\u003Cspan class=\"hljs-tag\">&lt;/\u003Cspan class=\"hljs-name\">ConfigContext.Provider\u003C/span>&gt;\u003C/span>\u003C/span>\n\n\u003Cspan class=\"hljs-comment\">// ✅ After: Split into domain-specific contexts\u003C/span>\n\u003Cspan class=\"language-xml\">\u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">ModelConfigProvider\u003C/span> \u003Cspan class=\"hljs-attr\">value\u003C/span>=\u003Cspan class=\"hljs-string\">{modelConfigValue}\u003C/span>&gt;\u003C/span>\n  \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">DatasetConfigProvider\u003C/span> \u003Cspan class=\"hljs-attr\">value\u003C/span>=\u003Cspan class=\"hljs-string\">{datasetConfigValue}\u003C/span>&gt;\u003C/span>\n    \u003Cspan class=\"hljs-tag\">&lt;\u003Cspan class=\"hljs-name\">UIConfigProvider\u003C/span> \u003Cspan class=\"hljs-attr\">value\u003C/span>=\u003Cspan class=\"hljs-string\">{uiConfigValue}\u003C/span>&gt;\u003C/span>\n      {children}\n    \u003Cspan class=\"hljs-tag\">&lt;/\u003Cspan class=\"hljs-name\">UIConfigProvider\u003C/span>&gt;\u003C/span>\n  \u003Cspan class=\"hljs-tag\">&lt;/\u003Cspan class=\"hljs-name\">DatasetConfigProvider\u003C/span>&gt;\u003C/span>\n\u003Cspan class=\"hljs-tag\">&lt;/\u003Cspan class=\"hljs-name\">ModelConfigProvider\u003C/span>&gt;\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\u003C/div>\u003Cp>\u003Cstrong>Dify Reference\u003C/strong>: \u003Ccode>web/context/\u003C/code> directory structure\u003C/p>\n\u003Ch3>2. Workflow Node Components\u003C/h3>\n\u003Cp>\u003Cstrong>When\u003C/strong>: Refactoring workflow node components (\u003Ccode>web/app/components/workflow/nodes/\u003C/code>).\u003C/p>\n\u003Cp>\u003Cstrong>Conventions\u003C/strong>:\u003C/p>\n\u003Cul>\n\u003Cli>Keep node logic in \u003Ccode>use-interactions.ts\u003C/code>\u003C/li>\n\u003Cli>Extract panel UI to separate files\u003C/li>\n\u003Cli>Use \u003Ccode>_base\u003C/code> components for common patterns\u003C/li>\n\u003C/ul>\n\u003Cdiv class=\"md-code-block\">\u003Cpre>\u003Ccode class=\"hljs language-plaintext\">nodes/&lt;node-type&gt;/\n  ├── index.tsx              # Node registration\n  ├── node.tsx               # Node visual component\n  ├── panel.tsx              # Configuration panel\n  ├── use-interactions.ts    # Node-specific hooks\n  └── types.ts               # Type definitions\u003C/code>\u003C/pre>\u003C/div>\u003Ch3>3. Configuration Components\u003C/h3>\n\u003Cp>\u003Cstrong>When\u003C/strong>: Refactoring app configuration components.\u003C/p>\n\u003Cp>\u003Cstrong>Conventions\u003C/strong>:\u003C/p>\n\u003Cul>\n\u003Cli>Separate config sections into subdirectories\u003C/li>\n\u003Cli>Use existing patterns from \u003Ccode>web/app/components/app/configuration/\u003C/code>\u003C/li>\n\u003Cli>Keep feature toggles in dedicated components\u003C/li>\n\u003C/ul>\n\u003Ch3>4. Tool/Plugin Components\u003C/h3>\n\u003Cp>\u003Cstrong>When\u003C/strong>: Refactoring tool-related components (\u003Ccode>web/app/components/tools/\u003C/code>).\u003C/p>\n\u003Cp>\u003Cstrong>Conventions\u003C/strong>:\u003C/p>\n\u003Cul>\n\u003Cli>Follow existing modal patterns\u003C/li>\n\u003Cli>Use service hooks from \u003Ccode>web/service/use-tools.ts\u003C/code>\u003C/li>\n\u003Cli>Keep provider-specific logic isolated\u003C/li>\n\u003C/ul>\n\u003Ch2>Refactoring Workflow\u003C/h2>\n\u003Ch3>Step 1: Generate Refactoring Prompt\u003C/h3>\n\u003Cdiv class=\"md-code-block\">\u003Cdiv class=\"md-code-lang\">bash\u003C/div>\u003Cpre>\u003Ccode class=\"hljs language-bash\">pnpm refactor-component &lt;path&gt;\u003C/code>\u003C/pre>\u003C/div>\u003Cp>This command will:\u003C/p>\n\u003Cul>\n\u003Cli>Analyze component complexity and features\u003C/li>\n\u003Cli>Identify specific refactoring actions needed\u003C/li>\n\u003Cli>Generate a prompt for AI assistant (auto-copied to clipboard on macOS)\u003C/li>\n\u003Cli>Provide detailed requirements based on detected patterns\u003C/li>\n\u003C/ul>\n\u003Ch3>Step 2: Analyze Details\u003C/h3>\n\u003Cdiv class=\"md-code-block\">\u003Cdiv class=\"md-code-lang\">bash\u003C/div>\u003Cpre>\u003Ccode class=\"hljs language-bash\">pnpm analyze-component &lt;path&gt; --json\u003C/code>\u003C/pre>\u003C/div>\u003Cp>Identify:\u003C/p>\n\u003Cul>\n\u003Cli>Total complexity score\u003C/li>\n\u003Cli>Max function complexity\u003C/li>\n\u003Cli>Line count\u003C/li>\n\u003Cli>Features detected (state, effects, API, etc.)\u003C/li>\n\u003C/ul>\n\u003Ch3>Step 3: Plan\u003C/h3>\n\u003Cp>Create a refactoring plan based on detected features:\u003C/p>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Detected Feature\u003C/th>\n\u003Cth>Refactoring Action\u003C/th>\n\u003C/tr>\n\u003C/thead>\n\u003Ctbody>\u003Ctr>\n\u003Ctd>\u003Ccode>hasState: true\u003C/code> + \u003Ccode>hasEffects: true\u003C/code>\u003C/td>\n\u003Ctd>Extract custom hook\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>hasAPI: true\u003C/code>\u003C/td>\n\u003Ctd>Extract data/service hook\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>hasEvents: true\u003C/code> (many)\u003C/td>\n\u003Ctd>Extract event handlers\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>lineCount &gt; 300\u003C/code>\u003C/td>\n\u003Ctd>Split into sub-components\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>maxComplexity &gt; 50\u003C/code>\u003C/td>\n\u003Ctd>Simplify conditional logic\u003C/td>\n\u003C/tr>\n\u003C/tbody>\u003C/table>\n\u003Ch3>Step 4: Execute Incrementally\u003C/h3>\n\u003Col>\n\u003Cli>\u003Cstrong>Extract one piece at a time\u003C/strong>\u003C/li>\n\u003Cli>\u003Cstrong>Run lint, type-check, and tests after each extraction\u003C/strong>\u003C/li>\n\u003Cli>\u003Cstrong>Verify functionality before next step\u003C/strong>\u003C/li>\n\u003C/ol>\n\u003Cdiv class=\"md-code-block\">\u003Cpre>\u003Ccode class=\"hljs language-plaintext\">For each extraction:\n  ┌────────────────────────────────────────┐\n  │ 1. Extract code                        │\n  │ 2. Run: pnpm lint:fix                  │\n  │ 3. Run: pnpm type-check:tsgo           │\n  │ 4. Run: pnpm test                      │\n  │ 5. Test functionality manually         │\n  │ 6. PASS? → Next extraction             │\n  │    FAIL? → Fix before continuing       │\n  └────────────────────────────────────────┘\u003C/code>\u003C/pre>\u003C/div>\u003Ch3>Step 5: Verify\u003C/h3>\n\u003Cp>After refactoring:\u003C/p>\n\u003Cdiv class=\"md-code-block\">\u003Cdiv class=\"md-code-lang\">bash\u003C/div>\u003Cpre>\u003Ccode class=\"hljs language-bash\">\u003Cspan class=\"hljs-comment\"># Re-run refactor command to verify improvements\u003C/span>\npnpm refactor-component &lt;path&gt;\n\n\u003Cspan class=\"hljs-comment\"># If complexity &lt; 25 and lines &lt; 200, you&#x27;ll see:\u003C/span>\n\u003Cspan class=\"hljs-comment\"># ✅ COMPONENT IS WELL-STRUCTURED\u003C/span>\n\n\u003Cspan class=\"hljs-comment\"># For detailed metrics:\u003C/span>\npnpm analyze-component &lt;path&gt; --json\n\n\u003Cspan class=\"hljs-comment\"># Target metrics:\u003C/span>\n\u003Cspan class=\"hljs-comment\"># - complexity &lt; 50\u003C/span>\n\u003Cspan class=\"hljs-comment\"># - lineCount &lt; 300\u003C/span>\n\u003Cspan class=\"hljs-comment\"># - maxComplexity &lt; 30\u003C/span>\u003C/code>\u003C/pre>\u003C/div>\u003Ch2>Common Mistakes to Avoid\u003C/h2>\n\u003Ch3>❌ Over-Engineering\u003C/h3>\n\u003Cdiv class=\"md-code-block\">\u003Cdiv class=\"md-code-lang\">typescript\u003C/div>\u003Cpre>\u003Ccode class=\"hljs language-typescript\">\u003Cspan class=\"hljs-comment\">// ❌ Too many tiny hooks\u003C/span>\n\u003Cspan class=\"hljs-keyword\">const\u003C/span> \u003Cspan class=\"hljs-title function_\">useButtonText\u003C/span> = (\u003Cspan class=\"hljs-params\">\u003C/span>) =&gt; \u003Cspan class=\"hljs-title function_\">useState\u003C/span>(\u003Cspan class=\"hljs-string\">&#x27;Click&#x27;\u003C/span>)\n\u003Cspan class=\"hljs-keyword\">const\u003C/span> \u003Cspan class=\"hljs-title function_\">useButtonDisabled\u003C/span> = (\u003Cspan class=\"hljs-params\">\u003C/span>) =&gt; \u003Cspan class=\"hljs-title function_\">useState\u003C/span>(\u003Cspan class=\"hljs-literal\">false\u003C/span>)\n\u003Cspan class=\"hljs-keyword\">const\u003C/span> \u003Cspan class=\"hljs-title function_\">useButtonLoading\u003C/span> = (\u003Cspan class=\"hljs-params\">\u003C/span>) =&gt; \u003Cspan class=\"hljs-title function_\">useState\u003C/span>(\u003Cspan class=\"hljs-literal\">false\u003C/span>)\n\n\u003Cspan class=\"hljs-comment\">// ✅ Cohesive hook with related state\u003C/span>\n\u003Cspan class=\"hljs-keyword\">const\u003C/span> \u003Cspan class=\"hljs-title function_\">useButtonState\u003C/span> = (\u003Cspan class=\"hljs-params\">\u003C/span>) =&gt; {\n  \u003Cspan class=\"hljs-keyword\">const\u003C/span> [text, setText] = \u003Cspan class=\"hljs-title function_\">useState\u003C/span>(\u003Cspan class=\"hljs-string\">&#x27;Click&#x27;\u003C/span>)\n  \u003Cspan class=\"hljs-keyword\">const\u003C/span> [disabled, setDisabled] = \u003Cspan class=\"hljs-title function_\">useState\u003C/span>(\u003Cspan class=\"hljs-literal\">false\u003C/span>)\n  \u003Cspan class=\"hljs-keyword\">const\u003C/span> [loading, setLoading] = \u003Cspan class=\"hljs-title function_\">useState\u003C/span>(\u003Cspan class=\"hljs-literal\">false\u003C/span>)\n  \u003Cspan class=\"hljs-keyword\">return\u003C/span> { text, setText, disabled, setDisabled, loading, setLoading }\n}\u003C/code>\u003C/pre>\u003C/div>\u003Ch3>❌ Breaking Existing Patterns\u003C/h3>\n\u003Cul>\n\u003Cli>Follow existing directory structures\u003C/li>\n\u003Cli>Maintain naming conventions\u003C/li>\n\u003Cli>Preserve export patterns for compatibility\u003C/li>\n\u003C/ul>\n\u003Ch3>❌ Premature Abstraction\u003C/h3>\n\u003Cul>\n\u003Cli>Only extract when there&#39;s clear complexity benefit\u003C/li>\n\u003Cli>Don&#39;t create abstractions for single-use code\u003C/li>\n\u003Cli>Keep refactored code in the same domain area\u003C/li>\n\u003C/ul>\n\u003Ch2>References\u003C/h2>\n\u003Ch3>Dify Codebase Examples\u003C/h3>\n\u003Cul>\n\u003Cli>\u003Cstrong>Hook extraction\u003C/strong>: \u003Ccode>web/app/components/app/configuration/hooks/\u003C/code>\u003C/li>\n\u003Cli>\u003Cstrong>Component splitting\u003C/strong>: \u003Ccode>web/app/components/app/configuration/\u003C/code>\u003C/li>\n\u003Cli>\u003Cstrong>Service hooks\u003C/strong>: \u003Ccode>web/service/use-*.ts\u003C/code>\u003C/li>\n\u003Cli>\u003Cstrong>Workflow patterns\u003C/strong>: \u003Ccode>web/app/components/workflow/hooks/\u003C/code>\u003C/li>\n\u003Cli>\u003Cstrong>Form patterns\u003C/strong>: \u003Ccode>web/app/components/base/form/\u003C/code>\u003C/li>\n\u003C/ul>\n\u003Ch3>Related Skills\u003C/h3>\n\u003Cul>\n\u003Cli>\u003Ccode>frontend-testing\u003C/code> - For testing refactored components\u003C/li>\n\u003Cli>\u003Ccode>web/docs/test.md\u003C/code> - Testing specification\u003C/li>\n\u003C/ul>\n"]