@hualinge/relay-web 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +31 -0
- package/dist/assets/AgentsPage-2u2kFBCH.js +68 -0
- package/dist/assets/AgentsPage-2u2kFBCH.js.map +1 -0
- package/dist/assets/AgentsPage-BGbbVmeL.css +1 -0
- package/dist/assets/Alert-D88Fk6to.js +2 -0
- package/dist/assets/Alert-D88Fk6to.js.map +1 -0
- package/dist/assets/AppModal-BYZTSuch.js +2 -0
- package/dist/assets/AppModal-BYZTSuch.js.map +1 -0
- package/dist/assets/CenteredLoadingState-DHor-9vF.js +2 -0
- package/dist/assets/CenteredLoadingState-DHor-9vF.js.map +1 -0
- package/dist/assets/ChannelsPage-CbI0kqkd.js +2 -0
- package/dist/assets/ChannelsPage-CbI0kqkd.js.map +1 -0
- package/dist/assets/EmptyDataState-6mNx2Xhl.js +2 -0
- package/dist/assets/EmptyDataState-6mNx2Xhl.js.map +1 -0
- package/dist/assets/HelpPrompt-BPzDcC8F.js +2 -0
- package/dist/assets/HelpPrompt-BPzDcC8F.js.map +1 -0
- package/dist/assets/HomePage-t78sDDUj.js +2 -0
- package/dist/assets/HomePage-t78sDDUj.js.map +1 -0
- package/dist/assets/InspirationPage-BTqLpcHY.js +3 -0
- package/dist/assets/InspirationPage-BTqLpcHY.js.map +1 -0
- package/dist/assets/ModelsPage-YF0gpUxy.js +2 -0
- package/dist/assets/ModelsPage-YF0gpUxy.js.map +1 -0
- package/dist/assets/NameInitialIcon-DP-6_HQY.js +7 -0
- package/dist/assets/NameInitialIcon-DP-6_HQY.js.map +1 -0
- package/dist/assets/NoSearchResultsState-BiiYdZ_Z.js +2 -0
- package/dist/assets/NoSearchResultsState-BiiYdZ_Z.js.map +1 -0
- package/dist/assets/OverflowTooltip-CE5PjAb-.js +2 -0
- package/dist/assets/OverflowTooltip-CE5PjAb-.js.map +1 -0
- package/dist/assets/PasswordField-DmzjtnCg.js +2 -0
- package/dist/assets/PasswordField-DmzjtnCg.js.map +1 -0
- package/dist/assets/RefreshButton-BzYzeo5A.js +2 -0
- package/dist/assets/RefreshButton-BzYzeo5A.js.map +1 -0
- package/dist/assets/RightContentHeader-DoNDQ9Lo.js +3 -0
- package/dist/assets/RightContentHeader-DoNDQ9Lo.js.map +1 -0
- package/dist/assets/SchedulePage-CfW6lZVI.js +2 -0
- package/dist/assets/SchedulePage-CfW6lZVI.js.map +1 -0
- package/dist/assets/SearchInput-tux8xXH1.js +2 -0
- package/dist/assets/SearchInput-tux8xXH1.js.map +1 -0
- package/dist/assets/SkillAvatar-DwGvsY4f.js +2 -0
- package/dist/assets/SkillAvatar-DwGvsY4f.js.map +1 -0
- package/dist/assets/SkillsPage-ppqwKMvj.js +2 -0
- package/dist/assets/SkillsPage-ppqwKMvj.js.map +1 -0
- package/dist/assets/SkillsTab-c_As1DIr.css +1 -0
- package/dist/assets/SkillsTab-kY7MNdxy.js +2 -0
- package/dist/assets/SkillsTab-kY7MNdxy.js.map +1 -0
- package/dist/assets/Tab-FE0F2EQP.js +2 -0
- package/dist/assets/Tab-FE0F2EQP.js.map +1 -0
- package/dist/assets/ThreadPage-B0jElW5R.js +53 -0
- package/dist/assets/ThreadPage-B0jElW5R.js.map +1 -0
- package/dist/assets/UploadSkillModal-DHZL12vm.js +8 -0
- package/dist/assets/UploadSkillModal-DHZL12vm.js.map +1 -0
- package/dist/assets/XlsxDocumentPreview-BY-ht09K.js +5 -0
- package/dist/assets/XlsxDocumentPreview-BY-ht09K.js.map +1 -0
- package/dist/assets/_commonjs-dynamic-modules-TDtrdbi3.js +2 -0
- package/dist/assets/_commonjs-dynamic-modules-TDtrdbi3.js.map +1 -0
- package/dist/assets/chat-input-options-CpkOtPgQ.js +2 -0
- package/dist/assets/chat-input-options-CpkOtPgQ.js.map +1 -0
- package/dist/assets/docx-preview-zfB-orwa.js +28 -0
- package/dist/assets/docx-preview-zfB-orwa.js.map +1 -0
- package/dist/assets/exceljs.min-BY7KKJsM.js +58 -0
- package/dist/assets/exceljs.min-BY7KKJsM.js.map +1 -0
- package/dist/assets/helpers-CCilgpNy.js +2 -0
- package/dist/assets/helpers-CCilgpNy.js.map +1 -0
- package/dist/assets/hub-agent-editor.client-2DmCRGuY.js +2 -0
- package/dist/assets/hub-agent-editor.client-2DmCRGuY.js.map +1 -0
- package/dist/assets/hub-agent-editor.payload-D4sgJRSH.js +4 -0
- package/dist/assets/hub-agent-editor.payload-D4sgJRSH.js.map +1 -0
- package/dist/assets/hub-tag-editor-BBdd-aHK.js +2 -0
- package/dist/assets/hub-tag-editor-BBdd-aHK.js.map +1 -0
- package/dist/assets/index-Bed0I5IL.css +1 -0
- package/dist/assets/index-Bxf2_cvh.js +2 -0
- package/dist/assets/index-Bxf2_cvh.js.map +1 -0
- package/dist/assets/index-Cb4fQgom.js +103 -0
- package/dist/assets/index-Cb4fQgom.js.map +1 -0
- package/dist/assets/index-DQ2vVjmV.js +30 -0
- package/dist/assets/index-DQ2vVjmV.js.map +1 -0
- package/dist/assets/index-UBJEdbMO.js +2 -0
- package/dist/assets/index-UBJEdbMO.js.map +1 -0
- package/dist/assets/jszip.min-DPdj3o0t.js +13 -0
- package/dist/assets/jszip.min-DPdj3o0t.js.map +1 -0
- package/dist/assets/quick-actions-DzZE-zyP.js +2 -0
- package/dist/assets/quick-actions-DzZE-zyP.js.map +1 -0
- package/dist/assets/skill-options-cache-D1BJGTCU.js +2 -0
- package/dist/assets/skill-options-cache-D1BJGTCU.js.map +1 -0
- package/dist/assets/status-helpers-BILdm2MI.js +2 -0
- package/dist/assets/status-helpers-BILdm2MI.js.map +1 -0
- package/dist/assets/thread-title-Cerb2mHa.js +2 -0
- package/dist/assets/thread-title-Cerb2mHa.js.map +1 -0
- package/dist/assets/thread-utils-Ct3yp4R3.js +2 -0
- package/dist/assets/thread-utils-Ct3yp4R3.js.map +1 -0
- package/dist/assets/useAgentData-D-k9cXfg.js +2 -0
- package/dist/assets/useAgentData-D-k9cXfg.js.map +1 -0
- package/dist/assets/useEscapeKey-CEQ6-8GR.js +2 -0
- package/dist/assets/useEscapeKey-CEQ6-8GR.js.map +1 -0
- package/dist/assets/useExpertCatalog-BZdw1CYs.js +2 -0
- package/dist/assets/useExpertCatalog-BZdw1CYs.js.map +1 -0
- package/dist/assets/usePromptBlocks-5sz8Qh51.js +2 -0
- package/dist/assets/usePromptBlocks-5sz8Qh51.js.map +1 -0
- package/dist/assets/useSocket-YigidotN.css +1 -0
- package/dist/assets/useSocket-y3-zWhVL.js +11 -0
- package/dist/assets/useSocket-y3-zWhVL.js.map +1 -0
- package/dist/assets/utils--_pbLpCq.js +2 -0
- package/dist/assets/utils--_pbLpCq.js.map +1 -0
- package/dist/assets/vad-web-C_R267y1.js +2 -0
- package/dist/assets/vad-web-C_R267y1.js.map +1 -0
- package/dist/avatars/agent-avatar-1.png +0 -0
- package/dist/avatars/agent-avatar-2.png +0 -0
- package/dist/avatars/agent-avatar-3.png +0 -0
- package/dist/avatars/agent-avatar-4.png +0 -0
- package/dist/avatars/agent-avatar-5.png +0 -0
- package/dist/avatars/agent-avatar-6.png +0 -0
- package/dist/avatars/agent-avatar-7.png +0 -0
- package/dist/avatars/agent-avatar-8.png +0 -0
- package/dist/avatars/agent-avatar-9.png +0 -0
- package/dist/avatars/agentteams.png +0 -0
- package/dist/avatars/antig-opus.png +0 -0
- package/dist/avatars/antigravity.png +0 -0
- package/dist/avatars/assistant.svg +17 -0
- package/dist/avatars/codex-kawaii.png +0 -0
- package/dist/avatars/codex.png +0 -0
- package/dist/avatars/codex_box.png +0 -0
- package/dist/avatars/codex_iquid.png +0 -0
- package/dist/avatars/dare.png +0 -0
- package/dist/avatars/gemini-kawaii.png +0 -0
- package/dist/avatars/gemini.png +0 -0
- package/dist/avatars/gemini25.png +0 -0
- package/dist/avatars/gpt52.png +0 -0
- package/dist/avatars/jiuwenclaw.png +0 -0
- package/dist/avatars/office.svg +17 -0
- package/dist/avatars/opencode.png +0 -0
- package/dist/avatars/opus-45.png +0 -0
- package/dist/avatars/opus-kawaii.png +0 -0
- package/dist/avatars/opus.png +0 -0
- package/dist/avatars/sonnet.png +0 -0
- package/dist/favicon.ico +0 -0
- package/dist/icons/arrow-left.svg +3 -0
- package/dist/icons/arrow-right.svg +3 -0
- package/dist/icons/attach.svg +9 -0
- package/dist/icons/chart/dislike.svg +3 -0
- package/dist/icons/chart/disliked.svg +3 -0
- package/dist/icons/chart/folder.svg +15 -0
- package/dist/icons/chart/home-loading.webp +0 -0
- package/dist/icons/chart/like.svg +3 -0
- package/dist/icons/chart/liked.svg +5 -0
- package/dist/icons/chart/loading.svg +26 -0
- package/dist/icons/chart/success.svg +7 -0
- package/dist/icons/check-line.svg +3 -0
- package/dist/icons/chevron-left.svg +3 -0
- package/dist/icons/chevron-right.svg +3 -0
- package/dist/icons/collapse.svg +14 -0
- package/dist/icons/common-delete.svg +4 -0
- package/dist/icons/common-folder.svg +4 -0
- package/dist/icons/copy.svg +4 -0
- package/dist/icons/cross-line.svg +4 -0
- package/dist/icons/data-analysis.svg +7 -0
- package/dist/icons/data-visualization.svg +10 -0
- package/dist/icons/deep-research.svg +4 -0
- package/dist/icons/document-processing.svg +5 -0
- package/dist/icons/edit.svg +4 -0
- package/dist/icons/expand.svg +6 -0
- package/dist/icons/expert-debate.svg +4 -0
- package/dist/icons/eye.svg +4 -0
- package/dist/icons/favicon.svg +7 -0
- package/dist/icons/file-docx.svg +60 -0
- package/dist/icons/file-folder.svg +4 -0
- package/dist/icons/file-gitignore.svg +35 -0
- package/dist/icons/file-html.svg +6 -0
- package/dist/icons/file-ini.svg +63 -0
- package/dist/icons/file-json.svg +4 -0
- package/dist/icons/file-md.svg +68 -0
- package/dist/icons/file-py.svg +4 -0
- package/dist/icons/file-sh.svg +7 -0
- package/dist/icons/file-txt.svg +37 -0
- package/dist/icons/file-zip.svg +21 -0
- package/dist/icons/file.svg +4 -0
- package/dist/icons/files-csv.svg +14 -0
- package/dist/icons/files-docx.svg +10 -0
- package/dist/icons/files-pdf.svg +14 -0
- package/dist/icons/files-ppt.svg +14 -0
- package/dist/icons/files-txt.svg +16 -0
- package/dist/icons/files-xlsx.svg +14 -0
- package/dist/icons/financial-services.svg +8 -0
- package/dist/icons/flie-html.svg +60 -0
- package/dist/icons/guided-mode.svg +9 -0
- package/dist/icons/icon-192x192.png +0 -0
- package/dist/icons/icon-512x512.png +0 -0
- package/dist/icons/icon-arrow-down.svg +4 -0
- package/dist/icons/icon-arrow-up.svg +4 -0
- package/dist/icons/icon-clear-all.svg +3 -0
- package/dist/icons/icon-close.svg +4 -0
- package/dist/icons/icon-code.svg +38 -0
- package/dist/icons/icon-drag-file.svg +26 -0
- package/dist/icons/icon-help.svg +4 -0
- package/dist/icons/icon-md.svg +53 -0
- package/dist/icons/icon-refresh.svg +4 -0
- package/dist/icons/icon-toggle.svg +6 -0
- package/dist/icons/icon-top.svg +7 -0
- package/dist/icons/icon-upload.svg +5 -0
- package/dist/icons/information.svg +6 -0
- package/dist/icons/inspiration/icon-excel.svg +14 -0
- package/dist/icons/inspiration/icon-inspiration.svg +5 -0
- package/dist/icons/inspiration/icon-markdown.svg +12 -0
- package/dist/icons/inspiration/icon-word.svg +10 -0
- package/dist/icons/link.svg +6 -0
- package/dist/icons/lock.svg +4 -0
- package/dist/icons/menu/agents.svg +39 -0
- package/dist/icons/menu/channels.svg +4 -0
- package/dist/icons/menu/icon-inspiration.svg +5 -0
- package/dist/icons/menu/models.svg +4 -0
- package/dist/icons/menu/new-chat.svg +59 -0
- package/dist/icons/menu/schedule.svg +4 -0
- package/dist/icons/menu/skills.svg +4 -0
- package/dist/icons/message-error.svg +6 -0
- package/dist/icons/message-prompt.svg +9 -0
- package/dist/icons/message-success.svg +6 -0
- package/dist/icons/message-warn.svg +8 -0
- package/dist/icons/more-trigger.svg +4 -0
- package/dist/icons/nss/1.svg +14 -0
- package/dist/icons/nss/2.svg +14 -0
- package/dist/icons/nss/3.svg +14 -0
- package/dist/icons/outline.svg +6 -0
- package/dist/icons/query_the_optical_power_border.svg +99 -0
- package/dist/icons/schedule.svg +4 -0
- package/dist/icons/settings-feedback/feedback-bug.svg +20 -0
- package/dist/icons/settings-feedback/feedback-file.svg +4 -0
- package/dist/icons/settings-feedback/feedback-idea.svg +14 -0
- package/dist/icons/settings-feedback/settings-gear.svg +4 -0
- package/dist/icons/settings-feedback/settings-link.svg +4 -0
- package/dist/icons/settings-feedback/settings-memory.svg +7 -0
- package/dist/icons/settings-feedback/settings-privacy.svg +37 -0
- package/dist/icons/settings-feedback/settings-search.svg +2 -0
- package/dist/icons/slides.svg +4 -0
- package/dist/icons/status/info-error.svg +9 -0
- package/dist/icons/style-template.svg +11 -0
- package/dist/icons/tool-error.svg +4 -0
- package/dist/icons/userprofile/help.svg +5 -0
- package/dist/icons/userprofile/keep-awake.svg +4 -0
- package/dist/icons/userprofile/question.svg +4 -0
- package/dist/icons/userprofile/security.svg +7 -0
- package/dist/icons/userprofile/style-template.svg +11 -0
- package/dist/icons/userprofile/theme.svg +14 -0
- package/dist/icons/userprofile/usage.svg +4 -0
- package/dist/icons/userprofile/version.svg +85 -0
- package/dist/icons/video-generation.svg +4 -0
- package/dist/images/OfficeClaw.svg +21 -0
- package/dist/images/add.svg +4 -0
- package/dist/images/agent-management-icons/agent-check.svg +23 -0
- package/dist/images/agent-management-icons/agent-close.svg +4 -0
- package/dist/images/agent-management-icons/agent-collab.svg +4 -0
- package/dist/images/agent-management-icons/agent-delete.svg +18 -0
- package/dist/images/agent-management-icons/agent-edit.svg +18 -0
- package/dist/images/agent-management-icons/agent-more.svg +4 -0
- package/dist/images/agent-management-icons/agent-persona.svg +4 -0
- package/dist/images/agent-management-icons/agent-random-avatar.svg +39 -0
- package/dist/images/agent-management-icons/agent-refresh.svg +4 -0
- package/dist/images/agent-management-icons/agent-skills.svg +4 -0
- package/dist/images/agent-management-icons/agent-template.svg +12 -0
- package/dist/images/agent-management-icons/anchor-current.svg +5 -0
- package/dist/images/agent-management-icons/anchor-other.svg +4 -0
- package/dist/images/chat-empty-agent.svg +12 -0
- package/dist/images/chat-empty-im.svg +14 -0
- package/dist/images/connectors/dingtalk.png +0 -0
- package/dist/images/connectors/dingtalk.svg +18 -0
- package/dist/images/connectors/feishu.png +0 -0
- package/dist/images/connectors/feishu.svg +12 -0
- package/dist/images/connectors/imessage.png +0 -0
- package/dist/images/connectors/wecom-agent.png +0 -0
- package/dist/images/connectors/wecom-bot.png +0 -0
- package/dist/images/connectors/weixin.png +0 -0
- package/dist/images/connectors/weixin.svg +19 -0
- package/dist/images/connectors/xiaoyi.png +0 -0
- package/dist/images/connectors/xiaoyi.svg +12 -0
- package/dist/images/create-agent-random-avatar.svg +39 -0
- package/dist/images/deepseek.svg +1 -0
- package/dist/images/default-ppt-template.png +0 -0
- package/dist/images/file-browser-tree/code.svg +60 -0
- package/dist/images/file-browser-tree/gitignore.svg +35 -0
- package/dist/images/file-browser-tree/image.svg +12 -0
- package/dist/images/file-browser-tree/markdown.svg +68 -0
- package/dist/images/file-browser-tree/pdf.svg +4 -0
- package/dist/images/file-browser-tree/ppt.svg +4 -0
- package/dist/images/file-browser-tree/public-file.svg +37 -0
- package/dist/images/file-browser-tree/word.svg +60 -0
- package/dist/images/file-browser-tree/xlsx.svg +4 -0
- package/dist/images/html-preview-toolbar/copy.svg +4 -0
- package/dist/images/html-preview-toolbar/open-external.svg +4 -0
- package/dist/images/html-preview-toolbar/refresh.svg +4 -0
- package/dist/images/information.svg +4 -0
- package/dist/images/inspiration/blue-bg.png +0 -0
- package/dist/images/inspiration/doc-example.png +0 -0
- package/dist/images/inspiration/excel-example.png +0 -0
- package/dist/images/inspiration/green-bg.png +0 -0
- package/dist/images/inspiration/markdown-example.png +0 -0
- package/dist/images/inspiration/orange-bg.png +0 -0
- package/dist/images/inspiration/purple-bg.png +0 -0
- package/dist/images/inspiration/task-bg.png +0 -0
- package/dist/images/inspiration-bg.png +0 -0
- package/dist/images/inspiration-products/default.svg +11 -0
- package/dist/images/invitation-background-4x.png +0 -0
- package/dist/images/kimi.svg +1 -0
- package/dist/images/link-blue.svg +4 -0
- package/dist/images/link.svg +4 -0
- package/dist/images/lobster.svg +118 -0
- package/dist/images/login1.svg +93 -0
- package/dist/images/login2.svg +80 -0
- package/dist/images/login3.svg +44 -0
- package/dist/images/login4.svg +18 -0
- package/dist/images/mode-default-icon.svg +22 -0
- package/dist/images/no-data.svg +26 -0
- package/dist/images/no-search-results.svg +25 -0
- package/dist/images/ppt-preview/placeholder-main.webp +0 -0
- package/dist/images/ppt-preview/placeholder-thumb.webp +0 -0
- package/dist/images/ppt-template/dark-tech.png +0 -0
- package/dist/images/ppt-template/huawei.png +0 -0
- package/dist/images/ppt-template/light-tech.png +0 -0
- package/dist/images/ppt-template/paper-humanities.png +0 -0
- package/dist/images/ppt-template/template-default.png +0 -0
- package/dist/images/ppt-template/template-error.png +0 -0
- package/dist/images/ppt-template/template-generate-bg.svg +9639 -0
- package/dist/images/qwen.svg +1 -0
- package/dist/images/task-list/empty-state.svg +4 -0
- package/dist/images/task-list.svg +1 -0
- package/dist/images/vendor.svg +4 -0
- package/dist/images/version-bg.svg +85 -0
- package/dist/images/version.svg +9 -0
- package/dist/images/zhipu.svg +1 -0
- package/dist/index.html +74 -0
- package/dist/loading-point-style.webp +0 -0
- package/dist/loading-small.webp +0 -0
- package/dist/manifest.json +25 -0
- package/package.json +126 -0
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{r as t,c as ye,u as pe,j as e,B as X,M as ie,b as Ve}from"./index-Cb4fQgom.js";import{u as ze}from"./useEscapeKey-CEQ6-8GR.js";import{a as V,g as We,b as Je,r as Ge,c as Ne,O as Ee}from"./OverflowTooltip-CE5PjAb-.js";import{C as Qe}from"./CenteredLoadingState-DHor-9vF.js";import{E as Ye}from"./EmptyDataState-6mNx2Xhl.js";import{N as Xe}from"./NoSearchResultsState-BiiYdZ_Z.js";import{b as Ze,n as et,r as tt,i as st,c as at,g as ot,d as rt,h as lt,e as nt,D as Ie,f as it,j as ve,k as dt,l as Se,m as we,o as ct,q as ut,s as mt,t as Re,u as pt,M as ht,v as Ue,w as Pe,S as xt,x as _e,y as Ae,z as ft,V as ke,H as yt,A as vt,T as Te,B as gt,E as bt,G as Le,I as jt,J as wt,K as Mt,L as Ct,N as Nt,O as Et,P as St}from"./utils--_pbLpCq.js";import{S as At}from"./SearchInput-tux8xXH1.js";import{N as kt,b as It}from"./NameInitialIcon-DP-6_HQY.js";import{P as De}from"./PasswordField-DmzjtnCg.js";import{u as Rt}from"./hub-agent-editor.client-2DmCRGuY.js";import{A as Ut}from"./AppModal-BYZTSuch.js";import{T as Pt}from"./hub-tag-editor-BBdd-aHK.js";function _t(){const[s,r]=t.useState(!1),[o,d]=t.useState(!1),[x,y]=t.useState(!1),[p,N]=t.useState(""),[l,M]=t.useState([]),[a,U]=t.useState(null),u=ye(v=>v.currentProjectPath),h=t.useCallback(()=>{const v=new URLSearchParams;u&&u!=="default"&&v.set("projectPath",u);const j=v.toString();return j?`/api/maas-models?${j}`:"/api/maas-models"},[u]),m=t.useCallback(()=>{const v=new URLSearchParams;u&&u!=="default"&&v.set("projectPath",u);const j=v.toString();return j?`/api/model-config-profiles?${j}`:"/api/model-config-profiles"},[u]),C=t.useCallback(async()=>{r(!0);try{const[v,j]=await Promise.all([V(h()),V(m())]);if(!v.ok){M([]);return}const f=await v.json(),B=j.ok?await j.json():{providers:[]},_=new Map((B.providers??[]).filter(w=>Ze(w.updatedAt??w.createdAt)!==void 0).map(w=>[w.id,w.updatedAt??w.createdAt])),J=Array.isArray(f.list)?f.list:Array.isArray(f.models)?f.models:[];M(J.map(et).map(w=>{const L=tt(w.id);if(!L||w.updatedAt!==void 0)return w;const I=_.get(L);return I?{...w,updatedAt:I}:w})),U(typeof f.projectPath=="string"?f.projectPath:null)}catch{M([])}finally{r(!1)}},[m,h]);t.useEffect(()=>{d(We()),y(Je()||st(Ge("CAN_CREATE_MODEL")))},[]),t.useEffect(()=>{C()},[C]);const n=t.useMemo(()=>p.trim().toLowerCase(),[p]),S=t.useMemo(()=>n?l.filter(v=>at(v).includes(n)):l,[l,n]),E=t.useMemo(()=>ot(S),[S]),P=n.length>0,R=!s&&l.length===0,b=!s&&l.length>0&&P&&E.length===0,T=!s&&E.length>0;return{loading:s,isSkipAuth:o,canCreateModel:x,searchQuery:p,setSearchQuery:N,cards:l,groupedCards:E,resolvedProjectPath:a,fetchModels:C,hasSearchQuery:P,showEmptyData:R,showNoResults:b,showGroups:T}}function Tt(){const[s,r]=t.useState([]),[o,d]=t.useState(new Map),[x,y]=t.useState(null),p=t.useCallback(h=>{const m=new Map,C=new Map;return h.forEach((n,S)=>{const E=n.key.trim(),P=n.value.trim(),R={};if(!E&&!P){m.set(n.id,{});return}if(!E&&P&&(R.keyError="请填写键名"),E&&!P&&(R.valueError="请填写值"),E){const b=C.get(E)||[];b.push(S),C.set(E,b)}Object.keys(R).length>0&&m.set(n.id,R)}),C.forEach((n,S)=>{n.length>1&&n.forEach(E=>{const P=h[E].id,R=m.get(P)||{};m.set(P,{...R,keyError:`键名"${S}"重复`})})}),d(m),m},[]),N=t.useCallback(()=>{const h=p(s);if(Array.from(h.values()).some(n=>!!(n&&(n.keyError||n.valueError))))return;const C=rt();r(n=>[...n,C]),p([...s,C])},[s,p]),l=t.useCallback((h,m,C)=>{const n=s.map(S=>S.id===h?{...S,[m]:C}:S);r(n),p(n)},[s,p]),M=t.useCallback(h=>{const m=s.filter(C=>C.id!==h);r(m),p(m)},[s,p]),a=t.useCallback(()=>{r([]),d(new Map),y(null)},[]),U=t.useCallback(()=>{d(new Map),y(null)},[]),u=t.useCallback(h=>{r(lt(h)),d(new Map),y(null)},[]);return{rows:s,rowErrors:o,errorRowIndex:x,handleAddRow:N,handleRowChange:l,handleRemoveRow:M,validateRows:p,resetRows:a,clearErrors:U,setErrorRowIndex:y,setRowsFromHeaders:u}}function Lt(s,r){const o=ye(g=>g.currentProjectPath),[d,x]=t.useState(!1),[y,p]=t.useState("default"),[N,l]=t.useState(null),[M,a]=t.useState(null),[U,u]=t.useState(!1),[h,m]=t.useState(""),[C,n]=t.useState(""),[S,E]=t.useState(""),[P,R]=t.useState(""),[b,T]=t.useState(""),[v,j]=t.useState(""),[f,B]=t.useState(null),[_,J]=t.useState(null),[w,L]=t.useState([]),[I,D]=t.useState({}),[O,z]=t.useState({}),[G,c]=t.useState({}),[$,F]=t.useState(!1),[W,Q]=t.useState(!1),k=Tt(),oe=!!f,he=y===ve,A=t.useCallback(()=>s||(o&&o!=="default"?o:void 0),[s,o]),re=h.trim(),le=re.length>=2&&re.length<=64&&nt(re),Ke=re.length>0&&!le,ge=oe?le:le&&(b==null?void 0:b.trim().length)>0&&(v==null?void 0:v.trim().length)>0,de=t.useCallback((g="default")=>{m(""),n(""),E(Ie),R(""),T(g===ve?it:""),j(""),k.resetRows()},[k]),be=t.useCallback(()=>{x(!1),p("default"),l(null),a(null),B(null),J(null),L([]),D({}),z({}),c({}),k.clearErrors()},[k]),je=t.useCallback((g="default")=>{de(g),p(g),B(null),J(null),L([]),D({}),z({}),c({}),l(null),k.clearErrors(),a(null),x(!0)},[de,k]),Oe=t.useCallback(()=>{Q(!0)},[]),$e=t.useCallback(()=>{Q(!1)},[]),Be=t.useCallback(()=>{Q(!1),je("default")},[je]),Me=t.useCallback(()=>{if(!f)return[h.trim()].filter(Boolean);const g=h.trim(),K=(_==null?void 0:_.trim())||"",q=(w.length>0?[...w]:K?[K]:[]).map(H=>H===K?g:H);return Array.from(new Set((q.length>0?q:[g]).map(H=>H.trim()).filter(Boolean)))},[f,h,_,w]),He=t.useCallback(async()=>{if(!ge||U)return;const g=dt(k.rows);if(g.errorIndex!==null||g.errorMessage){k.setErrorRowIndex(g.errorIndex),k.validateRows(k.rows);return}k.setErrorRowIndex(null),l(null),a(null),u(!0);try{const K=C.trim(),Y=P.trim(),q=S.trim(),H=A();let Z="POST",xe="/api/model-config-profiles",ce;if(f){Z="PUT",xe=`/api/model-config-profiles/${encodeURIComponent(f)}`;const fe=Me(),te=(_==null?void 0:_.trim())||"",se=h.trim(),me=Object.fromEntries(fe.map(ae=>{const Ce=ae===se&&(b.trim()||I[te])||I[ae];return Ce?[ae,Ce]:null}).filter(ae=>ae!==null)),ne={...O},i={...G};te&&te!==se&&(delete ne[te],delete i[te]),K?ne[se]=K:delete ne[se],q?i[se]=q:delete i[se],ce={...Y?{displayName:Y}:{},...b.trim()?{baseUrl:b.trim()}:{},...v.trim()?{apiKey:v.trim()}:{},...g.headers?{headers:g.headers}:{},models:fe,...Object.keys(me).length>0?{modelBaseUrls:me}:{},modelDescriptions:ne,modelIcons:i,...H?{projectPath:H}:{}}}else ce={sourceId:we(),...Y?{displayName:Y}:{},...K?{description:K}:{},...q?{icon:q}:{},...he?{accessMode:Se}:{},baseUrl:b.trim(),apiKey:v.trim(),...g.headers?{headers:g.headers}:{},models:[h.trim()],...H?{projectPath:H}:{}};const ue=await V(xe,{method:Z,headers:{"content-type":"application/json"},body:JSON.stringify(ce)}),ee=await ue.json().catch(()=>({}));if(!ue.ok)throw new Error(ee.error??`请求失败 (${ue.status})`);de(),be(),await r()}catch(K){l(K instanceof Error?K.message:String(K))}finally{u(!1)}},[ge,U,k,C,P,S,b,v,f,_,I,O,G,Me,he,h,A,de,be,r]),Fe=t.useCallback(async()=>{const g=b.trim(),K=v.trim(),Y=h.trim();if(!g||!K)return;u(!0),l(null),a(null);const q=pe.getState().addToast;try{const H=await V("/api/maas-test-connection",{method:"POST",headers:{"content-type":"application/json"},suppressAuthRedirect:!0,body:JSON.stringify({baseUrl:g,...K&&!(f&&K.includes("****"))?{apiKey:K}:{},model:Y||"default",...f?{sourceId:f}:{},...A()?{projectPath:A()}:{}})}),Z=await H.json().catch(()=>({}));if(!H.ok||Z.error)throw new Error(Z.error??`HTTP ${H.status}`);q({type:"success",title:"测试连接成功",message:"连接测试成功",duration:3e3})}catch{q({type:"error",title:"测试连接失败",message:"请检查模型调用名称或者API Key填写是否正确",duration:5e3})}finally{u(!1)}},[b,v,h,f,A]),qe=t.useCallback(async g=>{var Y,q,H,Z,xe,ce,ue;const K=Dt(g.id);if(!(!K||$)){de("default"),p(g.accessMode===Se||(Y=g.baseUrl)!=null&&Y.includes("modelarts-maas")?ve:"default"),l(null),a(null),F(!0),k.clearErrors();try{const ee=A(),fe=new URLSearchParams;ee&&fe.set("projectPath",ee);const te=fe.toString(),se=`/api/model-config-profiles${te?`?${te}`:""}`,me=await V(se),ne=await me.json().catch(()=>({}));if(!me.ok)throw new Error(ne.error??`请求失败 (${me.status})`);const i=(ne.providers??[]).find(ae=>ae.id===K);B(K),J(g.name),L(Array.isArray(i==null?void 0:i.models)?i.models:[g.name]),D((i==null?void 0:i.modelBaseUrls)??{}),z((i==null?void 0:i.modelDescriptions)??{}),c((i==null?void 0:i.modelIcons)??{}),m(g.name),n(((q=i==null?void 0:i.modelDescriptions)==null?void 0:q[g.name])??g.description??(i==null?void 0:i.description)??""),R((i==null?void 0:i.displayName)??""),E(((Z=(H=i==null?void 0:i.modelIcons)==null?void 0:H[g.name])==null?void 0:Z.trim())||((xe=i==null?void 0:i.icon)==null?void 0:xe.trim())||((ce=g.icon)==null?void 0:ce.trim())||""),T(((ue=i==null?void 0:i.modelBaseUrls)==null?void 0:ue[g.name])??g.baseUrl??(i==null?void 0:i.baseUrl)??""),j((i==null?void 0:i.apiKey)??""),k.setRowsFromHeaders(i==null?void 0:i.headers),x(!0)}catch(ee){l(ee instanceof Error?ee.message:String(ee))}finally{F(!1)}}},[$,de,k,A]);return{showModal:d,openModal:je,closeModal:be,modalMode:y,modelNameInput:h,setModelNameInput:m,modelDescriptionInput:C,setModelDescriptionInput:n,modelIconInput:S,setModelIconInput:E,modelDisplayNameInput:P,setModelDisplayNameInput:R,modelUrlInput:b,setModelUrlInput:T,modelApiKeyInput:v,setModelApiKeyInput:j,headerRows:k.rows,headerRowErrors:k.rowErrors,headerErrorRowIndex:k.errorRowIndex,handleAddHeaderRow:k.handleAddRow,handleHeaderRowChange:k.handleRowChange,handleRemoveHeaderRow:k.handleRemoveRow,isModelNameValid:le,showModelNameValidationError:Ke,canConfirm:ge,isEditMode:oe,editingSourceId:f,editingOriginalModelName:_,editingSourceModels:w,editModelBusy:$,handleOpenEditModelModal:qe,createError:N,createModelSuccess:M,saveModelBusy:U,handleCreateModel:He,handleTestConnection:Fe,showRiskModal:W,openRiskModal:Oe,closeRiskModal:$e,handleAgreeRisk:Be,resolveProjectPathForPayload:A}}function Dt(s){var d;if(!s.startsWith("model_config:"))return null;const r=s.split(":");if(r.length<3)return null;const o=(d=r[1])==null?void 0:d.trim();return o||null}function Kt(s,r,o){const[d,x]=t.useState(()=>we()),[y,p]=t.useState(""),[N,l]=t.useState(""),[M,a]=t.useState(""),[U,u]=t.useState(""),[h,m]=t.useState([]),[C,n]=t.useState(!1),[S,E]=t.useState(null),[P,R]=t.useState(null),b=y.trim().length>0&&N.trim().length>0&&M.trim().length>0&&h.length>0,T=t.useCallback(()=>{x(we()),p(""),l(""),a(""),u(""),m([]),E(null),R(null)},[]),v=t.useCallback(async()=>{R(null),n(!0);try{const j=ct(U),f=await V("/api/model-config-profiles",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({...s?{projectPath:s}:{},sourceId:d.trim(),displayName:y.trim(),baseUrl:N.trim(),apiKey:M.trim(),...j?{headers:j}:{},models:h})}),B=await f.json().catch(()=>({}));if(!f.ok)throw new Error(B.error??`请求失败 (${f.status})`);T(),await r()}catch(j){const f=j instanceof Error?j.message:String(j);E(f)}finally{n(!1)}},[s,d,y,N,M,U,h,T,r,o]);return{sourceId:d,displayName:y,baseUrl:N,apiKey:M,headersText:U,models:h,setDisplayName:p,setBaseUrl:l,setApiKey:a,setHeadersText:u,setModels:m,canCreate:b,saveBusy:C,error:S,successMessage:P,handleSave:v,reset:T}}function Ot(s,r,o){var f,B,_,J;const d=ye(w=>w.currentProjectPath),[x,y]=t.useState("claw-plan"),[p,N]=t.useState(""),[l,M]=t.useState({}),[a,U]=t.useState(!1),[u,h]=t.useState(!1),[m,C]=t.useState(!1),n=d&&d!=="default"?d:void 0,S=((f=l[x])==null?void 0:f.apiKey)||((B=l["claw-plan"])==null?void 0:B.apiKey)||((_=l.maas)==null?void 0:_.apiKey)||"",E=S.trim().length>0,P=(E&&!m||p.trim().length>0)&&!a&&!u,R=((J=Ne("PUBLIC_MAAS_API_KEY_URL"))==null?void 0:J.trim())||ut,b=t.useMemo(()=>n?`/api/model-config-profiles?${new URLSearchParams({projectPath:n}).toString()}`:"/api/model-config-profiles",[n]),T=t.useCallback(async()=>{var w,L;U(!0);try{const I=await V(b),D=await I.json().catch(()=>({}));if(!I.ok){M({});return}const O={};for(const G of D.providers??[]){const c=mt(G);c&&!O[c]&&(O[c]=G)}M(O);const z=((w=O["claw-plan"])==null?void 0:w.apiKey)||((L=O.maas)==null?void 0:L.apiKey)||"";z&&N(z)}finally{U(!1)}},[b]);t.useEffect(()=>{s&&T()},[s,T]),t.useEffect(()=>{!s||m||!S||N(S)},[S,s,m]),t.useEffect(()=>{s||(y("claw-plan"),N(""),M({}),C(!1))},[s]);const v=t.useCallback(()=>{C(!0),N("")},[]),j=t.useCallback(async()=>{var D;if(E&&!m){r();return}const w=p.trim();if(!w||u)return;const L=Re[x],I=l[x];h(!0);try{let O,z;if(x==="maas"){const k=await V("/api/maas-models-query",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({baseUrl:L.baseUrl,apiKey:w})}),oe=await k.json().catch(()=>({}));if(!k.ok)throw new Error(oe.error??`查询已购模型失败 (${k.status})`);O=Array.isArray(oe.models)?oe.models.map(A=>typeof(A==null?void 0:A.id)=="string"?A.id.trim():"").filter(A=>A.length>0):[];const he=(oe.models??[]).map(A=>{const re=typeof(A==null?void 0:A.id)=="string"?A.id.trim():"",le=typeof(A==null?void 0:A.baseUrl)=="string"?A.baseUrl.trim():"";return re&&le?[re,le]:null}).filter(A=>A!==null);if(he.length>0&&(z=Object.fromEntries(he)),O.length===0)throw new Error("未查询到已购模型,请确认 API Key 是否正确或是否已购买模型。")}else O=pt(x,(D=Ne("PUBLIC_CLAW_PLAN_MODELS"))==null?void 0:D.trim());const G=(I==null?void 0:I.id)||L.sourceId,c={displayName:L.displayName,baseUrl:L.baseUrl,apiKey:w,serviceType:x,...O.length>0?{models:O}:{},...z?{modelBaseUrls:z}:{},...n?{projectPath:n}:{}},$=!!(I!=null&&I.id),F=$?`/api/model-config-profiles/${encodeURIComponent(G)}`:"/api/model-config-profiles",W=await V(F,{method:$?"PUT":"POST",headers:{"content-type":"application/json"},body:JSON.stringify($?c:{...c,sourceId:G})}),Q=await W.json().catch(()=>({}));if(!W.ok)throw new Error(Q.error??`请求失败 (${W.status})`);pe.getState().addToast({type:"success",title:"模型接入成功。",message:"模型接入成功。",duration:3e3}),C(!1),r(),await o()}catch{pe.getState().addToast({type:"error",title:"模型接入失败,请核对接入信息后重试。",message:"模型接入失败,请核对接入信息后重试。",duration:5e3})}finally{h(!1)}},[E,x,p,r,o,n,l,u,m]);return{activeServiceType:x,setActiveServiceType:y,apiKey:p,setApiKey:N,loading:a,saving:u,canConfirm:P,activeHasApiKey:E,updatingApiKey:m,apiKeyUrl:R,startApiKeyUpdate:v,handleConfirm:j}}function $t({loading:s,isSkipAuth:r,canCreateModel:o,searchQuery:d,onSearchChange:x,onRefresh:y,onOpenCreateModel:p,onOpenHuaweiMaasAccess:N}){const l=ye(M=>M.openHub);return e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"ui-page-header-inline mb-4",children:[e.jsx("h1",{className:"ui-page-title",children:ht}),e.jsxs("div",{className:"flex items-center justify-end gap-2",children:[e.jsx("button",{type:"button",onClick:()=>l("provider-profiles"),className:"hidden rounded-[16px] border border-[var(--button-default-border)] bg-[var(--button-default-bg)] px-3 py-1.5 text-[12px] font-medium text-[var(--button-default-text)] transition-colors hover:border-[var(--button-default-border-hover)] hover:bg-[var(--button-default-bg-hover)] hover:text-[var(--button-default-text-hover)]",children:"ACP / 账号配置"}),r?null:e.jsx(X,{variant:"major",onClick:N,"data-testid":"models-open-huawei-maas-model-modal",children:Ue}),o?e.jsx(X,{variant:"major",onClick:p,"data-testid":"models-open-create-model-modal",children:Pe}):null]})]}),e.jsx("section",{className:"shrink-0 pb-6","data-testid":"models-toolbar",children:e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(At,{wrapperClassName:"flex-1","aria-label":"搜索模型",value:d,onChange:x,onClear:()=>x(""),placeholder:xt,clearAriaLabel:"清除搜索"}),e.jsx("button",{type:"button","aria-label":"刷新",title:"刷新","data-testid":"models-refresh-button",onClick:y,disabled:s,className:"inline-flex h-[28px] w-[28px] shrink-0 items-center justify-center rounded-[8px] border border-[var(--border-default)] bg-[var(--surface-panel)] text-[var(--text-secondary)] transition-colors hover:bg-[var(--surface-hover)] hover:text-[var(--text-primary)] disabled:cursor-not-allowed disabled:opacity-50",children:e.jsx(ie,{name:"refresh",className:"h-4 w-4"})})]})})]})}function Bt(){return e.jsxs("svg",{className:"h-4 w-4 shrink-0",viewBox:"0 0 24 24",fill:"none","aria-hidden":"true",children:[e.jsx("circle",{cx:"12",cy:"12",r:"8",stroke:"currentColor",strokeWidth:"1.8"}),e.jsx("path",{d:"M12 7.5V12L15 13.8",stroke:"currentColor",strokeWidth:"1.8",strokeLinecap:"round"})]})}function Ht({card:s,groupKey:r,deletingModelId:o,editModelBusy:d,onEdit:x,onDelete:y}){const p=_e(s.icon),N=s.protocol!==Ae?ft(s.updatedAt):null;return e.jsxs("article",{className:["ui-card",r===yt?null:"ui-card-hover","group flex min-h-[194px] flex-col gap-4"].filter(Boolean).join(" "),children:[e.jsx("div",{children:e.jsxs("div",{className:"flex items-start gap-3",children:[p?e.jsx("img",{src:p,alt:`${s.name} icon`,width:48,height:48,className:"h-12 w-12 shrink-0 rounded-[var(radius-xs)] object-cover","data-testid":`model-card-icon-${s.id}`}):e.jsx("div",{className:"h-12 w-12 shrink-0 rounded-[var(radius-xs)]",children:e.jsx(kt,{name:s.name,dataTestId:`model-card-icon-${s.id}`,className:"h-full w-full rounded-[var(--radius-md)] border-0 shadow-none"})}),e.jsxs("div",{className:"min-w-0 flex-1",children:[e.jsx("div",{className:"flex items-start justify-between gap-2",children:e.jsx(Ee,{content:s.name,className:"min-w-0 flex-1",as:"h4",textClassName:"block truncate text-[var(--font-size-xl)] font-semibold text-[var(--text-primary)]"})}),s.labels.length>0?e.jsx("div",{className:"mt-1 flex flex-wrap items-center gap-1.5",children:s.labels.map((l,M)=>e.jsx("span",{className:"ui-badge-muted",children:l},`${s.id}-label-${l}-${M}`))}):null]})]})}),e.jsx(Ee,{content:s.description,className:"w-full",children:e.jsx("p",{className:"text-[14px] min-h-[44px] leading-[22px] text-[var(--text-secondary)] line-clamp-2 break-all overflow-hidden",children:s.description||s.name})}),e.jsx("div",{className:"flex items-end justify-between gap-3",children:e.jsx("div",{className:"min-h-5 text-xs leading-[24px]",children:s.protocol!==Ae?e.jsxs("div",{className:"relative",children:[e.jsx("span",{className:"inline-flex items-center gap-1.5 text-[var(--text-muted)] transition-opacity duration-200 group-hover:opacity-0",children:N?e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"inline-flex h-4 w-4 items-center justify-center","data-testid":`model-card-updated-at-icon-${s.id}`,children:e.jsx(Bt,{})}),e.jsx("span",{"data-testid":`model-card-updated-at-${s.id}`,children:N})]}):e.jsxs(e.Fragment,{children:[e.jsx("img",{src:ke,alt:`${s.developer} icon`,width:16,height:16,className:"h-4 w-4 rounded-sm object-cover"}),e.jsx("span",{children:s.developer})]})}),e.jsxs("div",{className:"absolute left-0 top-0 flex items-center whitespace-nowrap opacity-0 transition-opacity duration-200 group-hover:opacity-100",children:[e.jsx("button",{type:"button","data-testid":`model-card-edit-${s.id}`,disabled:d,onClick:()=>x(s),className:"whitespace-nowrap text-[14px] font-bold leading-[24px] text-[var(--text-accent)] hover:underline hover:underline-offset-2 disabled:opacity-50",style:{textUnderlineOffset:"4px"},children:"编辑"}),e.jsx("button",{type:"button",disabled:o===s.id,onClick:()=>y(s.id,s.name),"data-testid":`model-card-delete-${s.id}`,className:"ml-[24px] whitespace-nowrap text-[14px] font-bold leading-[24px] text-[var(--text-accent)] hover:underline hover:underline-offset-2 disabled:opacity-50",style:{textUnderlineOffset:"4px"},children:o===s.id?"删除中...":"删除"})]})]}):e.jsxs("span",{className:"inline-flex items-center gap-1.5 text-[var(--text-muted)]",children:[e.jsx("img",{src:ke,alt:`${s.developer} icon`,width:16,height:16,className:"h-4 w-4 rounded-sm object-cover"}),e.jsx("span",{children:s.developer})]})})})]})}function Ft({group:s,deletingModelId:r,editModelBusy:o,onEdit:d,onDelete:x}){return e.jsxs("section",{className:"space-y-3",children:[e.jsxs("h3",{className:"text-[14px] font-semibold text-[var(--text-primary)] mb-4",children:[s.label," (",s.items.length,")"]}),e.jsx("div",{className:"grid grid-cols-1 gap-3 md:grid-cols-2 xl:grid-cols-3",children:s.items.map(y=>e.jsx(Ht,{card:y,groupKey:s.key,deletingModelId:r,editModelBusy:o,onEdit:d,onDelete:x},y.id))})]})}function qt(){return e.jsx(ie,{name:"close",className:"h-4 w-4"})}function Vt({show:s,onClose:r,modalMode:o,isEditMode:d,modelNameInput:x,onModelNameChange:y,modelDescriptionInput:p,onModelDescriptionChange:N,modelIconInput:l,onModelIconChange:M,modelDisplayNameInput:a,onModelDisplayNameChange:U,modelUrlInput:u,onModelUrlChange:h,modelApiKeyInput:m,onModelApiKeyChange:C,headerRows:n,headerRowErrors:S,headerErrorRowIndex:E,onAddHeaderRow:P,onHeaderRowChange:R,onRemoveHeaderRow:b,showModelNameValidationError:T,canConfirm:v,createError:j,saveModelBusy:f,testingConnection:B,editModelBusy:_,onCreate:J,onTestConnection:w}){const L=t.useRef(null),[I,D]=t.useState(!1),O=o===ve,z=_e(l)??Ie;t.useEffect(()=>{if(E!==null){const c=document.querySelector('[data-error-row="true"]');c==null||c.scrollIntoView({behavior:"smooth",block:"center"})}},[E]);const G=async c=>{var W;const $=(W=c.target.files)==null?void 0:W[0];if(!$)return;if(!["image/png","image/jpeg","image/jpg"].includes($.type)){pe.getState().addToast({type:"error",title:"图标格式不支持",message:"仅支持 png、jpeg、jpg 格式图片",duration:3e3}),c.target.value="";return}if($.size>jt){pe.getState().addToast({type:"error",title:"图标文件过大",message:"图片大小不能超过 200KB",duration:3e3}),c.target.value="";return}D(!0);try{const Q=await Rt($);M(Q)}catch(Q){pe.getState().addToast({type:"error",title:"图标上传失败",message:Q instanceof Error?Q.message:"图标上传失败",duration:3e3})}finally{D(!1),c.target.value=""}};return s?e.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-[var(--overlay-backdrop-strong)] p-4","data-testid":"models-create-model-modal",children:e.jsxs("div",{className:"relative flex w-[500px] max-h-[calc(100vh-4rem)] flex-col gap-5 overflow-hidden rounded-[8px] border border-[var(--modal-border)] bg-[var(--modal-surface)] p-6 shadow-[var(--modal-shadow)]",children:[e.jsx("button",{type:"button",onClick:r,"aria-label":"close",className:"absolute right-5 top-5 flex h-6 w-6 items-center justify-center rounded text-[var(--modal-close-icon)] transition-colors hover:bg-[var(--modal-close-hover-bg)] hover:text-[var(--modal-close-icon-hover)]",children:e.jsx(qt,{})}),e.jsx("div",{className:"pr-10",children:e.jsx("h3",{className:"text-[16px] font-bold text-[var(--modal-title-text)]",children:d?"编辑":O?Ue:Pe})}),e.jsxs("div",{className:"min-h-0 flex-1 space-y-4 overflow-y-auto pr-1",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx("p",{className:"text-[12px] leading-[18px] text-[var(--modal-text)]",children:O?"模型调用名称":"模型名称"}),e.jsx("input",{"data-testid":"models-create-model-name-input",value:x,onChange:c=>y(c.target.value),placeholder:O?"请输入模型调用名称":"请输入模型名称",className:"ui-input w-full",style:{height:"28px"},required:!0}),T?e.jsx("p",{"data-testid":"models-create-model-name-error",className:"mt-1 text-xs text-[var(--state-error-text)]",children:vt}):null]}),e.jsxs("div",{className:"space-y-2.5",children:[e.jsx("div",{className:"text-[12px] text-[var(--text-primary)]",children:"模型描述(可选)"}),e.jsx(Te,{"data-testid":"models-create-model-description-textarea",value:p,onChange:c=>N(c.target.value),placeholder:"请输入描述",maxLength:500,showCount:!0,formatCount:(c,$)=>`${c}/${$??0}`,className:"h-[60px] min-h-[60px] w-full"})]}),e.jsxs("div",{className:"hidden space-y-1",children:[e.jsx("p",{className:"text-[12px] leading-[18px] text-[var(--modal-text)]",children:"模型展示名称"}),e.jsx("input",{"data-testid":"models-create-model-display-name-input",value:a,onChange:c=>U(c.target.value),placeholder:"请输入模型展示名称",className:"ui-input w-full",style:{height:"28px"},required:!0})]}),e.jsxs("div",{className:"space-y-2.5",children:[e.jsx("div",{className:"text-[12px] text-[var(--text-primary)]",children:"图标(可选)"}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsxs("button",{type:"button","aria-label":"Upload model icon",onClick:()=>{var c;return(c=L.current)==null?void 0:c.click()},className:"group relative flex h-11 w-11 items-center justify-center rounded-[var(--radius-xs)] transition overflow-hidden",children:[e.jsx("img",{src:z,alt:"Model icon preview",className:"h-full w-full object-cover"}),e.jsx("span",{className:"pointer-events-none absolute inset-0 flex items-center justify-center bg-[var(--modal-loading-overlay)] opacity-0 transition group-hover:opacity-100",children:e.jsx(ie,{name:"edit",preserveOriginalColor:!0,className:"h-4 w-4"})})]}),e.jsx("input",{ref:L,type:"file",accept:"image/png,image/jpeg,image/jpg",onChange:G,className:"hidden","data-testid":"models-create-model-icon-file-input"}),e.jsx("div",{className:"h-11 pt-[22px]",children:e.jsx("div",{"aria-hidden":"true",className:"h-[16px] w-px bg-[var(--border-default)]"})}),e.jsx("div",{className:"h-11 pt-[16px]",children:e.jsx("button",{type:"button","aria-label":"Random model icon",onClick:()=>{const c=Math.floor(Math.random()*1e4);M(It(x,c))},className:"h-[28px] w-[28px] min-h-[28px] min-w-[28px] p-0",children:e.jsx(ie,{name:"random"})})})]}),e.jsx("div",{className:"text-[12px] text-[var(--text-muted)]",children:I?"图标上传中...":"支持上传 png、jpeg、jpg 格式图片,限制 200KB 内"})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx("p",{className:"text-[12px] leading-[18px] text-[var(--modal-text)]",children:"访问URL"}),e.jsx("input",{"data-testid":"models-create-model-url-input",name:"cc_model_base_url",value:u,onChange:c=>h(c.target.value),placeholder:"请输入访问URL",autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",spellCheck:!1,disabled:O,className:`ui-input w-full ${O?"cursor-not-allowed border-[var(--overlay-disabled-border)] bg-[var(--overlay-disabled-bg)] text-[var(--overlay-disabled-text)]":""}`,style:{height:"28px"},required:!0})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx("p",{className:"text-[12px] leading-[18px] text-[var(--modal-text)]",children:"API Key"}),e.jsx(De,{"data-testid":"models-create-model-api-key-input",name:"cc_model_api_key",value:m,onChange:c=>C(c.target.value),placeholder:"请输入API Key",autoComplete:"new-password",autoCorrect:"off",autoCapitalize:"off",spellCheck:!1,className:"ui-input w-full",style:{height:"28px"},required:!0,toggleTestId:"models-create-model-api-key-toggle"})]}),e.jsxs("div",{className:"space-y-1",children:[e.jsx("p",{className:"text-[12px] leading-[18px] text-[var(--modal-text)]",children:"请求头(可选)"}),e.jsxs("div",{className:"space-y-2",children:[n.map((c,$)=>{const F=S.get(c.id)||{};return e.jsxs("div",{className:"flex flex-col gap-1","data-testid":`models-create-model-header-row-${$}`,"data-error-row":F.keyError||F.valueError?"true":"false",children:[e.jsxs("div",{className:"flex items-center gap-[4px]",children:[e.jsx("input",{type:"text",value:c.key,onChange:W=>R(c.id,"key",W.target.value),placeholder:"请求头的键名",className:`ui-input h-[28px] flex-1 ${F.keyError?"border-[var(--state-error-text)] bg-[var(--state-error-surface)]":""}`,"data-testid":`models-create-model-header-key-${$}`}),e.jsx("input",{type:"text",value:c.value,onChange:W=>R(c.id,"value",W.target.value),placeholder:"请求头的值",className:`ui-input h-[28px] flex-1 ${F.valueError?"border-[var(--state-error-text)] bg-[var(--state-error-surface)]":""}`,"data-testid":`models-create-model-header-value-${$}`}),e.jsx("button",{type:"button",onClick:()=>b(c.id),"aria-label":`请求头 ${$+1}`,className:"inline-flex h-6 w-6 min-h-6 min-w-6 items-center justify-center rounded-[8px] p-0 text-[var(--icon-delete-color)] transition-colors hover:bg-[var(--modal-muted-surface-hover)]","data-testid":`models-create-model-header-remove-${$}`,children:e.jsx(ie,{name:"delete",className:"h-4 w-4"})})]}),(F.keyError||F.valueError)&&e.jsx("div",{className:"break-all px-1 text-xs text-[var(--state-error-text)]",children:F.keyError||F.valueError})]},c.id)}),e.jsxs("button",{type:"button",onClick:P,className:"group inline-flex items-center gap-[4px] leading-[18px] text-[12px] text-[var(--text-accent)]","data-testid":"models-create-model-header-add",children:[e.jsx(ie,{name:"add",className:"h-4 w-4"}),e.jsx("span",{className:"inline-flex h-[18px] items-center border-b border-transparent transition-colors group-hover:border-current",children:"添加"})]})]}),j&&j.includes("请求头键名重复")?e.jsx("p",{className:"mt-1 text-xs text-[var(--state-error-text)]",children:j}):null]})]}),e.jsxs("div",{className:"flex items-center justify-end gap-2",children:[e.jsx(X,{variant:"default",onClick:r,children:gt}),e.jsx(X,{variant:"default",disabled:!v||B||I||_,onClick:w,"data-testid":"models-test-connection",children:B?"测试中...":bt}),e.jsx(X,{disabled:!v||f||I||_,onClick:J,"data-testid":"models-create-model-confirm",children:f?"保存中...":Le})]})]})}):null}function zt({show:s,onClose:r,onAgree:o}){return e.jsx(Ut,{open:s,onClose:r,title:wt,panelClassName:"w-[550px]",disableBackdropClose:!0,showCloseButton:!0,backdropTestId:"models-create-model-risk-modal",panelTestId:"models-create-model-risk-modal-panel",children:e.jsxs("div",{className:"space-y-4 pt-[18px]",children:[e.jsx("p",{className:"text-[12px] leading-[18px] text-[var(--text-secondary)]",children:Mt}),e.jsxs("div",{className:"flex items-center justify-end gap-2",children:[e.jsx(X,{variant:"default",size:"md","data-testid":"models-create-model-risk-cancel",onClick:r,children:"取消"}),e.jsx(X,{variant:"major",size:"md","data-testid":"models-create-model-risk-confirm",onClick:o,children:"我已同意"})]})]})})}function Wt({show:s,onClose:r,form:o}){return s?e.jsx("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-[var(--overlay-backdrop-strong)] p-4","data-testid":"models-add-model-modal",children:e.jsxs("div",{className:"max-h-[90vh] w-full max-w-xl overflow-y-auto rounded-2xl border border-[var(--modal-border)] bg-[var(--modal-surface)] p-5 shadow-[var(--modal-shadow)]",children:[e.jsxs("div",{className:"mb-4 flex items-center justify-between",children:[e.jsx("h3",{className:"text-base font-semibold text-[var(--modal-title-text)]",children:Ct}),e.jsx("button",{type:"button",onClick:()=>{o.reset(),r()},className:"rounded-lg border border-[var(--button-default-border)] bg-[var(--button-default-bg)] px-3 py-1.5 text-xs font-medium text-[var(--button-default-text)] transition-colors hover:border-[var(--button-default-border-hover)] hover:bg-[var(--button-default-bg-hover)] hover:text-[var(--button-default-text-hover)]",children:"关闭"})]}),e.jsxs("div",{className:"space-y-3",children:[o.error?e.jsx("p",{className:"ui-status-error rounded-lg px-3 py-2 text-sm",children:o.error}):null,e.jsx("select",{value:"openai",disabled:!0,"aria-label":"协议",className:"w-full rounded border border-[var(--overlay-disabled-border)] bg-[var(--overlay-disabled-bg)] px-3 py-2 text-sm text-[var(--overlay-disabled-text)]",children:e.jsx("option",{value:"openai",children:"OpenAI"})}),e.jsx("input",{value:o.displayName,onChange:d=>o.setDisplayName(d.target.value),placeholder:"显示名称,如 My OpenAI Proxy",autoComplete:"off",className:"ui-input w-full"}),e.jsx("input",{value:o.baseUrl,onChange:d=>o.setBaseUrl(d.target.value),placeholder:"Base URL,如 https://api.example.com/v1",autoComplete:"off",className:"ui-input w-full"}),e.jsx(De,{autoComplete:"off",value:o.apiKey,onChange:d=>o.setApiKey(d.target.value),placeholder:"API Key",className:"ui-input w-full rounded px-3 py-2 text-sm",toggleTestId:"models-create-source-api-key-toggle"}),e.jsx(Te,{value:o.headersText,onChange:d=>o.setHeadersText(d.target.value),rows:4,placeholder:'可选请求头(JSON),如 {"X-App-Id":"my-app"}',useDefaultContainerStyles:!1,useDefaultTextareaStyles:!1,className:"ui-textarea w-full rounded px-3 py-2 text-sm"}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"text-xs font-semibold text-[var(--modal-text-muted)]",children:"可用模型 *"}),e.jsx(Pt,{tags:o.models,tone:"purple",addLabel:"+ 添加模型",placeholder:"输入模型名,如 gpt-4o-mini",emptyLabel:"(至少添加 1 个模型)",onChange:o.setModels,minCount:0})]}),o.successMessage?e.jsx("p",{className:"ui-status-success rounded-lg px-3 py-2 text-sm",children:o.successMessage}):null,e.jsx("div",{className:"flex items-center justify-end gap-2",children:e.jsx("button",{type:"button",disabled:o.saveBusy||!o.canCreate,onClick:()=>void o.handleSave(),className:"rounded bg-[var(--button-primary-bg)] px-3 py-1.5 text-xs font-medium text-[var(--button-primary-text)] transition-colors hover:bg-[var(--button-primary-bg-hover)] hover:text-[var(--button-primary-text-hover)] disabled:bg-[var(--button-disabled-bg)] disabled:text-[var(--button-disabled-text)] disabled:opacity-50",children:o.saveBusy?"保存中...":Le})})]})]})}):null}function Jt({show:s,activeServiceType:r,apiKey:o,loading:d,saving:x,canConfirm:y,activeHasApiKey:p,updatingApiKey:N,apiKeyUrl:l,onServiceTypeChange:M,onApiKeyChange:a,onUpdateApiKey:U,onClose:u,onConfirm:h}){return s?e.jsx("div",{className:"fixed inset-0 z-50 flex items-start justify-center bg-[var(--overlay-backdrop-strong)] px-4 pt-[96px]","data-testid":"models-huawei-maas-access-modal",children:e.jsxs("div",{className:"relative w-full max-w-[640px] rounded-[8px] border border-[var(--modal-border)] bg-[var(--modal-surface)] p-6 shadow-[var(--modal-shadow)]",children:[e.jsx("button",{type:"button",onClick:u,"aria-label":"close",className:"absolute right-5 top-5 flex h-6 w-6 items-center justify-center rounded text-[var(--modal-close-icon)] transition-colors hover:bg-[var(--modal-close-hover-bg)] hover:text-[var(--modal-close-icon-hover)]",children:e.jsx(ie,{name:"close",className:"h-4 w-4"})}),e.jsx("div",{className:"pr-10",children:e.jsx("h3",{className:"text-[16px] font-bold text-[var(--modal-title-text)]",children:"接入MaaS模型"})}),e.jsxs("div",{className:"mt-5 space-y-4",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx("div",{className:"text-[12px] leading-[18px] text-[var(--modal-text)]",children:"接入类型"}),e.jsx("div",{className:"flex flex-wrap gap-2",children:["claw-plan","maas"].map(m=>{const C=r===m;return e.jsx("button",{type:"button",onClick:()=>M(m),className:["h-[28px] min-w-[156px] rounded-[6px] border px-4 text-[12px] transition-colors",C?"border-[#1677ff] bg-white text-[#1677ff]":"border-[var(--border-default)] bg-[var(--surface-panel)] text-[var(--text-primary)] hover:border-[#1677ff]"].join(" "),"data-testid":`models-huawei-maas-service-${m}`,children:Re[m].label},m)})})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("div",{className:"text-[12px] leading-[18px] text-[var(--modal-text)]",children:"API Key"}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"text","data-testid":"models-huawei-maas-api-key-input",name:"huawei_maas_api_key",value:o,onChange:m=>a(m.target.value),placeholder:"立即创建或粘贴已有的“西南-贵阳一”API Key",autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",spellCheck:!1,disabled:p&&!N||d||x,className:"ui-input h-[28px] min-w-0 flex-1 disabled:bg-[#f3f4f6] disabled:text-[var(--text-muted)]"}),p&&!N?e.jsx("button",{type:"button",onClick:U,className:"shrink-0 text-[12px] text-[var(--text-accent)] hover:underline","data-testid":"models-huawei-maas-api-key-update",children:"更新"}):e.jsx("a",{href:l,target:"_blank",rel:"noopener noreferrer",className:"shrink-0 text-[12px] text-[var(--text-accent)] hover:underline",children:"创建API Key"})]})]})]}),e.jsxs("div",{className:"mt-5 flex items-center justify-end gap-2",children:[e.jsx(X,{variant:"default",onClick:u,disabled:x,children:"取消"}),e.jsx(X,{disabled:!y,loading:x,onClick:h,"data-testid":"models-huawei-maas-confirm",children:"确认"})]})]})}):null}function Gt(s){const r="model_config:";if(!s.startsWith(r))return null;const o=s.slice(r.length),d=o.indexOf(":");if(d<=0)return null;const x=o.slice(0,d).trim(),y=o.slice(d+1).trim();return x&&y?{sourceId:x,modelName:y}:null}function Qt(){const s=Ve(),r=ye(n=>n.currentProjectPath),[o,d]=t.useState(null),[x,y]=t.useState(!1),[p,N]=t.useState(!1),l=_t(),M=l.fetchModels,a=Lt(l.resolvedProjectPath,M),U=t.useCallback(()=>{N(!1)},[]),u=Ot(p,U,M),h=Kt(r&&r!=="default"?r:null,async()=>{await M(),y(!1)},()=>{}),m=t.useCallback(async(n,S)=>{var P,R;if(!(o||!await s({title:"删除模型",message:`确认删除模型"${S||n}"?此操作不可恢复。`,confirmLabel:"删除",cancelLabel:"取消",variant:"default"}))){d(n);try{let b=n;const T=Gt(n);T&&(b=T.sourceId);const v=new URLSearchParams;r&&r!=="default"&&v.set("projectPath",r);const j=v.toString();let f;if(T){const B=`/api/model-config-profiles${j?`?${j}`:""}`,_=await V(B);if(!_.ok){const D=await _.json().catch(()=>({}));throw new Error(D.error??`读取模型配置失败 (${_.status})`)}const w=(P=(await _.json().catch(()=>({}))).providers)==null?void 0:P.find(D=>D.id===b);if(!w)throw new Error(`模型源 "${b}" 不存在`);const L=((R=w.models)==null?void 0:R.map(D=>D.trim()).filter(Boolean))??[];if(!L.includes(T.modelName))throw new Error(`模型 "${T.modelName}" 不存在`);const I=L.filter(D=>D!==T.modelName);if(L.length>1&&I.length>0)f=await V(`/api/model-config-profiles/${encodeURIComponent(b)}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({...r&&r!=="default"?{projectPath:r}:{},models:I})});else{const D=`/api/model-config-profiles/${encodeURIComponent(b)}${j?`?${j}`:""}`;f=await V(D,{method:"DELETE"})}}else{const B=`/api/model-config-profiles/${encodeURIComponent(b)}${j?`?${j}`:""}`;f=await V(B,{method:"DELETE"})}if(!f.ok){const B=await f.json().catch(()=>({}));throw new Error(B.error??`删除失败 (${f.status})`)}await M()}catch(b){console.error("Delete model failed:",b)}finally{d(null)}}},[s,o,r,M]),C=t.useCallback(()=>{if(Nt()){a.openModal("default");return}a.openRiskModal()},[a]);return ze({enabled:a.showModal||a.showRiskModal||p,onEscape:()=>{if(p){U();return}if(a.showRiskModal){a.closeRiskModal();return}a.closeModal()}}),e.jsxs("div",{className:"ui-page-shell overflow-hidden",children:[e.jsx($t,{loading:l.loading,isSkipAuth:l.isSkipAuth,canCreateModel:l.canCreateModel,searchQuery:l.searchQuery,onSearchChange:l.setSearchQuery,onRefresh:()=>void l.fetchModels(),onOpenCreateModel:C,onOpenHuaweiMaasAccess:()=>N(!0)}),e.jsx("div",{className:"flex-1 min-h-0 overflow-y-auto pb-2","data-testid":"models-scroll-region",children:e.jsxs("div",{className:"flex flex-col gap-4 h-full",children:[l.loading&&e.jsx("div",{className:"flex flex-1 min-h-0 items-center justify-center py-10","data-testid":"models-loading-state",children:e.jsx(Qe,{})}),l.showEmptyData&&e.jsx("div",{className:"flex flex-1 min-h-0 items-center justify-center py-10","data-testid":"models-empty-state",children:e.jsx(Ye,{title:Et})}),l.showNoResults&&e.jsx("div",{className:"flex flex-1 min-h-0 items-center justify-center py-10","data-testid":"models-no-results-state",children:e.jsx(Xe,{onClear:()=>l.setSearchQuery("")})}),l.showGroups&&l.groupedCards.map(n=>e.jsx(Ft,{group:n,deletingModelId:o,editModelBusy:a.editModelBusy,onEdit:S=>void a.handleOpenEditModelModal(S),onDelete:m},n.key))]})}),e.jsx(zt,{show:a.showRiskModal,onClose:a.closeRiskModal,onAgree:()=>{St(),a.handleAgreeRisk()}}),e.jsx(Vt,{show:a.showModal,onClose:a.closeModal,modalMode:a.modalMode,isEditMode:a.isEditMode,modelNameInput:a.modelNameInput,onModelNameChange:a.setModelNameInput,modelDescriptionInput:a.modelDescriptionInput,onModelDescriptionChange:a.setModelDescriptionInput,modelIconInput:a.modelIconInput,onModelIconChange:a.setModelIconInput,modelDisplayNameInput:a.modelDisplayNameInput,onModelDisplayNameChange:a.setModelDisplayNameInput,modelUrlInput:a.modelUrlInput,onModelUrlChange:a.setModelUrlInput,modelApiKeyInput:a.modelApiKeyInput,onModelApiKeyChange:a.setModelApiKeyInput,headerRows:a.headerRows,headerRowErrors:a.headerRowErrors,headerErrorRowIndex:a.headerErrorRowIndex,onAddHeaderRow:a.handleAddHeaderRow,onHeaderRowChange:a.handleHeaderRowChange,onRemoveHeaderRow:a.handleRemoveHeaderRow,isModelNameValid:a.isModelNameValid,showModelNameValidationError:a.showModelNameValidationError,canConfirm:a.canConfirm,createError:a.createError,saveModelBusy:a.saveModelBusy,testingConnection:a.saveModelBusy,editModelBusy:a.editModelBusy,onCreate:()=>void a.handleCreateModel(),onTestConnection:()=>void a.handleTestConnection()}),e.jsx(Wt,{show:x,onClose:()=>{h.reset(),y(!1)},form:h}),e.jsx(Jt,{show:p,activeServiceType:u.activeServiceType,apiKey:u.apiKey,loading:u.loading,saving:u.saving,canConfirm:u.canConfirm,activeHasApiKey:u.activeHasApiKey,updatingApiKey:u.updatingApiKey,apiKeyUrl:u.apiKeyUrl,onServiceTypeChange:u.setActiveServiceType,onApiKeyChange:u.setApiKey,onUpdateApiKey:u.startApiKeyUpdate,onClose:U,onConfirm:()=>void u.handleConfirm()})]})}function cs(){return e.jsx("div",{className:"h-full overflow-hidden ui-shell-surface px-8 py-8",children:e.jsx(Qt,{})})}export{cs as default};
|
|
2
|
+
//# sourceMappingURL=ModelsPage-YF0gpUxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ModelsPage-YF0gpUxy.js","sources":["../../src/components/models-panel/hooks/useModelsPanelData.ts","../../src/components/models-panel/hooks/useHeaderRowsEditor.ts","../../src/components/models-panel/hooks/useCreateModelForm.ts","../../src/components/models-panel/hooks/useAddModelForm.ts","../../src/components/models-panel/hooks/useHuaweiMaasAccessForm.ts","../../src/components/models-panel/components/ModelsToolbar.tsx","../../src/components/models-panel/components/ModelCard.tsx","../../src/components/models-panel/components/ModelGroupSection.tsx","../../src/components/models-panel/components/CreateModelModal.tsx","../../src/components/models-panel/components/CreateModelRiskModal.tsx","../../src/components/models-panel/components/AddModelModal.tsx","../../src/components/models-panel/components/HuaweiMaasAccessModal.tsx","../../src/components/models-panel/ModelsPanel.tsx","../../src/pages/ModelsPage.tsx"],"sourcesContent":["/*\n * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n */\n\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { useChatStore } from '@/stores/chatStore';\nimport { apiFetch } from '@/utils/api-client';\nimport { readBuildEnv } from '@/utils/client-env';\nimport { getCanCreateModel, getIsSkipAuth } from '@/utils/userId';\nimport {\n buildModelSearchText,\n groupCards,\n isEnvFlagEnabled,\n normalizeModel,\n normalizeUpdatedAt,\n resolveModelConfigSourceId,\n} from '../utils';\nimport type { MassModelResponseItem, ModelCardData, ModelCardGroup, ModelConfigProviderItem } from '../types/models-panel';\n\nexport interface UseModelsPanelDataResult {\n loading: boolean;\n isSkipAuth: boolean;\n canCreateModel: boolean;\n searchQuery: string;\n setSearchQuery: (query: string) => void;\n cards: ModelCardData[];\n groupedCards: ModelCardGroup[];\n resolvedProjectPath: string | null;\n fetchModels: () => Promise<void>;\n hasSearchQuery: boolean;\n showEmptyData: boolean;\n showNoResults: boolean;\n showGroups: boolean;\n}\n\nexport function useModelsPanelData(): UseModelsPanelDataResult {\n const [loading, setLoading] = useState(false);\n const [isSkipAuth, setIsSkipAuth] = useState(false);\n const [canCreateModel, setCanCreateModel] = useState(false);\n const [searchQuery, setSearchQuery] = useState('');\n const [cards, setCards] = useState<ModelCardData[]>([]);\n const [resolvedProjectPath, setResolvedProjectPath] = useState<string | null>(null);\n\n const currentProjectPath = useChatStore((s) => s.currentProjectPath);\n\n const buildModelsUrl = useCallback(() => {\n const query = new URLSearchParams();\n if (currentProjectPath && currentProjectPath !== 'default') {\n query.set('projectPath', currentProjectPath);\n }\n const queryText = query.toString();\n return queryText ? `/api/maas-models?${queryText}` : '/api/maas-models';\n }, [currentProjectPath]);\n\n const buildModelConfigProfilesUrl = useCallback(() => {\n const query = new URLSearchParams();\n if (currentProjectPath && currentProjectPath !== 'default') {\n query.set('projectPath', currentProjectPath);\n }\n const queryText = query.toString();\n return queryText ? `/api/model-config-profiles?${queryText}` : '/api/model-config-profiles';\n }, [currentProjectPath]);\n\n const fetchModels = useCallback(async () => {\n setLoading(true);\n try {\n const [modelsRes, providersRes] = await Promise.all([\n apiFetch(buildModelsUrl()),\n apiFetch(buildModelConfigProfilesUrl()),\n ]);\n if (!modelsRes.ok) {\n setCards([]);\n return;\n }\n const json = (await modelsRes.json()) as {\n projectPath?: string;\n list?: MassModelResponseItem[];\n models?: MassModelResponseItem[];\n };\n const providersJson = providersRes.ok\n ? ((await providersRes.json()) as { providers?: ModelConfigProviderItem[] })\n : { providers: [] };\n const providerUpdatedAtById = new Map(\n (providersJson.providers ?? [])\n .filter((provider) => normalizeUpdatedAt(provider.updatedAt ?? provider.createdAt) !== undefined)\n .map((provider) => [provider.id, (provider.updatedAt ?? provider.createdAt) as string]),\n );\n const source = Array.isArray(json.list) ? json.list : Array.isArray(json.models) ? json.models : [];\n setCards(\n source.map(normalizeModel).map((card) => {\n const sourceId = resolveModelConfigSourceId(card.id);\n if (!sourceId || card.updatedAt !== undefined) return card;\n const updatedAt = providerUpdatedAtById.get(sourceId);\n return updatedAt ? { ...card, updatedAt } : card;\n }),\n );\n setResolvedProjectPath(typeof json.projectPath === 'string' ? json.projectPath : null);\n } catch {\n setCards([]);\n } finally {\n setLoading(false);\n }\n }, [buildModelConfigProfilesUrl, buildModelsUrl]);\n\n useEffect(() => {\n setIsSkipAuth(getIsSkipAuth());\n setCanCreateModel(\n getCanCreateModel() || isEnvFlagEnabled(readBuildEnv('CAN_CREATE_MODEL')),\n );\n }, []);\n\n useEffect(() => {\n void fetchModels();\n }, [fetchModels]);\n\n const normalizedQuery = useMemo(() => searchQuery.trim().toLowerCase(), [searchQuery]);\n\n const filteredCards = useMemo(() => {\n if (!normalizedQuery) return cards;\n return cards.filter((card) => buildModelSearchText(card).includes(normalizedQuery));\n }, [cards, normalizedQuery]);\n\n const groupedCards = useMemo(() => groupCards(filteredCards), [filteredCards]);\n\n const hasSearchQuery = normalizedQuery.length > 0;\n const showEmptyData = !loading && cards.length === 0;\n const showNoResults = !loading && cards.length > 0 && hasSearchQuery && groupedCards.length === 0;\n const showGroups = !loading && groupedCards.length > 0;\n\n return {\n loading,\n isSkipAuth,\n canCreateModel,\n searchQuery,\n setSearchQuery,\n cards,\n groupedCards,\n resolvedProjectPath,\n fetchModels,\n hasSearchQuery,\n showEmptyData,\n showNoResults,\n showGroups,\n };\n}","/*\n * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n */\n\nimport { useCallback, useState } from 'react';\nimport { createEmptyHeaderRow, headersObjectToRows } from '../utils';\nimport type { HeaderInputRow } from '../types/models-panel';\n\nexport interface UseHeaderRowsEditorResult {\n rows: HeaderInputRow[];\n rowErrors: Map<string, { keyError?: string; valueError?: string }>;\n errorRowIndex: number | null;\n handleAddRow: () => void;\n handleRowChange: (rowId: string, field: 'key' | 'value', value: string) => void;\n handleRemoveRow: (rowId: string) => void;\n validateRows: (rows: HeaderInputRow[]) => Map<string, { keyError?: string; valueError?: string }>;\n resetRows: () => void;\n clearErrors: () => void;\n setErrorRowIndex: (index: number | null) => void;\n setRowsFromHeaders: (headers?: Record<string, string> | null) => void;\n}\n\nexport function useHeaderRowsEditor(): UseHeaderRowsEditorResult {\n const [rows, setRows] = useState<HeaderInputRow[]>([]);\n const [rowErrors, setRowErrors] = useState<Map<string, { keyError?: string; valueError?: string }>>(new Map());\n const [errorRowIndex, setErrorRowIndex] = useState<number | null>(null);\n\n const validateRows = useCallback((targetRows: HeaderInputRow[]) => {\n const newErrors = new Map<string, { keyError?: string; valueError?: string }>();\n const keyCountMap = new Map<string, number[]>();\n\n targetRows.forEach((row, index) => {\n const key = row.key.trim();\n const value = row.value.trim();\n const rowErrors: { keyError?: string; valueError?: string } = {};\n\n if (!key && !value) {\n newErrors.set(row.id, {});\n return;\n }\n\n if (!key && value) {\n rowErrors.keyError = '请填写键名';\n }\n\n if (key && !value) {\n rowErrors.valueError = '请填写值';\n }\n\n if (key) {\n const existing = keyCountMap.get(key) || [];\n existing.push(index);\n keyCountMap.set(key, existing);\n }\n\n if (Object.keys(rowErrors).length > 0) {\n newErrors.set(row.id, rowErrors);\n }\n });\n\n keyCountMap.forEach((indices, key) => {\n if (indices.length > 1) {\n indices.forEach((index) => {\n const rowId = targetRows[index].id;\n const existing = newErrors.get(rowId) || {};\n newErrors.set(rowId, { ...existing, keyError: `键名\"${key}\"重复` });\n });\n }\n });\n\n setRowErrors(newErrors);\n return newErrors;\n }, []);\n\n const handleAddRow = useCallback(() => {\n const errors = validateRows(rows);\n const hasError = Array.from(errors.values()).some((err) => !!(err && (err.keyError || err.valueError)));\n if (hasError) {\n return;\n }\n\n const nextRow = createEmptyHeaderRow();\n setRows((prev) => [...prev, nextRow]);\n validateRows([...rows, nextRow]);\n }, [rows, validateRows]);\n\n const handleRowChange = useCallback(\n (rowId: string, field: 'key' | 'value', value: string) => {\n const updatedRows = rows.map((row) => (row.id === rowId ? { ...row, [field]: value } : row));\n setRows(updatedRows);\n validateRows(updatedRows);\n },\n [rows, validateRows],\n );\n\n const handleRemoveRow = useCallback(\n (rowId: string) => {\n const updatedRows = rows.filter((row) => row.id !== rowId);\n setRows(updatedRows);\n validateRows(updatedRows);\n },\n [rows, validateRows],\n );\n\n const resetRows = useCallback(() => {\n setRows([]);\n setRowErrors(new Map());\n setErrorRowIndex(null);\n }, []);\n\n const clearErrors = useCallback(() => {\n setRowErrors(new Map());\n setErrorRowIndex(null);\n }, []);\n\n const setRowsFromHeaders = useCallback((headers?: Record<string, string> | null) => {\n setRows(headersObjectToRows(headers));\n setRowErrors(new Map());\n setErrorRowIndex(null);\n }, []);\n\n return {\n rows,\n rowErrors,\n errorRowIndex,\n handleAddRow,\n handleRowChange,\n handleRemoveRow,\n validateRows,\n resetRows,\n clearErrors,\n setErrorRowIndex,\n setRowsFromHeaders,\n };\n}","/*\n * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n */\n\nimport { useCallback, useState } from 'react';\nimport { useChatStore } from '@/stores/chatStore';\nimport { useToastStore } from '@/stores/toastStore';\nimport { apiFetch } from '@/utils/api-client';\nimport {\n buildHeadersObject,\n DEFAULT_MODEL_ICON_SRC,\n generateModelConfigSourceId,\n HUAWEI_MAAS_ACCESS_URL,\n isValidModelName,\n HUAWEI_MAAS_ACCESS_MODE,\n HUAWEI_MAAS_ACCESS_MODAL_MODE,\n} from '../utils';\nimport { useHeaderRowsEditor } from './useHeaderRowsEditor';\nimport type { CreateModelModalMode, HeaderInputRow, ModelCardData, ModelConfigProviderItem } from '../types/models-panel';\n\nexport interface UseCreateModelFormResult {\n // Modal state\n showModal: boolean;\n openModal: (mode?: CreateModelModalMode) => void;\n closeModal: () => void;\n modalMode: CreateModelModalMode;\n\n // Form fields\n modelNameInput: string;\n setModelNameInput: (value: string) => void;\n modelDescriptionInput: string;\n setModelDescriptionInput: (value: string) => void;\n modelIconInput: string;\n setModelIconInput: (value: string) => void;\n modelDisplayNameInput: string;\n setModelDisplayNameInput: (value: string) => void;\n modelUrlInput: string;\n setModelUrlInput: (value: string) => void;\n modelApiKeyInput: string;\n setModelApiKeyInput: (value: string) => void;\n\n // Header rows\n headerRows: HeaderInputRow[];\n headerRowErrors: Map<string, { keyError?: string; valueError?: string }>;\n headerErrorRowIndex: number | null;\n handleAddHeaderRow: () => void;\n handleHeaderRowChange: (rowId: string, field: 'key' | 'value', value: string) => void;\n handleRemoveHeaderRow: (rowId: string) => void;\n\n // Validation\n isModelNameValid: boolean;\n showModelNameValidationError: boolean;\n canConfirm: boolean;\n\n // Edit mode\n isEditMode: boolean;\n editingSourceId: string | null;\n editingOriginalModelName: string | null;\n editingSourceModels: string[];\n editModelBusy: boolean;\n handleOpenEditModelModal: (card: ModelCardData) => Promise<void>;\n\n // Actions\n createError: string | null;\n createModelSuccess: string | null;\n saveModelBusy: boolean;\n handleCreateModel: () => Promise<void>;\n handleTestConnection: () => Promise<void>;\n\n // Risk modal\n showRiskModal: boolean;\n openRiskModal: () => void;\n closeRiskModal: () => void;\n handleAgreeRisk: () => void;\n\n // Utils\n resolveProjectPathForPayload: () => string | undefined;\n}\n\nexport function useCreateModelForm(\n resolvedProjectPath: string | null,\n fetchModels: () => Promise<void>,\n): UseCreateModelFormResult {\n const currentProjectPath = useChatStore((s) => s.currentProjectPath);\n\n const [showModal, setShowModal] = useState(false);\n const [modalMode, setModalMode] = useState<CreateModelModalMode>('default');\n const [createError, setCreateError] = useState<string | null>(null);\n const [createModelSuccess, setCreateModelSuccess] = useState<string | null>(null);\n const [saveModelBusy, setSaveModelBusy] = useState(false);\n\n const [modelNameInput, setModelNameInput] = useState('');\n const [modelDescriptionInput, setModelDescriptionInput] = useState('');\n const [modelIconInput, setModelIconInput] = useState('');\n const [modelDisplayNameInput, setModelDisplayNameInput] = useState('');\n const [modelUrlInput, setModelUrlInput] = useState('');\n const [modelApiKeyInput, setModelApiKeyInput] = useState('');\n\n const [editingSourceId, setEditingSourceId] = useState<string | null>(null);\n const [editingOriginalModelName, setEditingOriginalModelName] = useState<string | null>(null);\n const [editingSourceModels, setEditingSourceModels] = useState<string[]>([]);\n const [editingModelBaseUrls, setEditingModelBaseUrls] = useState<Record<string, string>>({});\n const [editingModelDescriptions, setEditingModelDescriptions] = useState<Record<string, string>>({});\n const [editingModelIcons, setEditingModelIcons] = useState<Record<string, string>>({});\n const [editModelBusy, setEditModelBusy] = useState(false);\n\n const [showRiskModal, setShowRiskModal] = useState(false);\n\n const headerEditor = useHeaderRowsEditor();\n\n const isEditMode = Boolean(editingSourceId);\n const isHuaweiMaasAccessMode = modalMode === HUAWEI_MAAS_ACCESS_MODAL_MODE;\n\n const resolveProjectPathForPayload = useCallback(\n () => resolvedProjectPath || (currentProjectPath && currentProjectPath !== 'default' ? currentProjectPath : undefined),\n [resolvedProjectPath, currentProjectPath],\n );\n\n const trimmedModelName = modelNameInput.trim();\n const isModelNameValid =\n trimmedModelName.length >= 2 && trimmedModelName.length <= 64 && isValidModelName(trimmedModelName);\n const showModelNameValidationError = trimmedModelName.length > 0 && !isModelNameValid;\n const canConfirm = isEditMode\n ? isModelNameValid\n : isModelNameValid && modelUrlInput?.trim().length > 0 && modelApiKeyInput?.trim().length > 0;\n\n const resetForm = useCallback((mode: CreateModelModalMode = 'default') => {\n setModelNameInput('');\n setModelDescriptionInput('');\n setModelIconInput(DEFAULT_MODEL_ICON_SRC);\n setModelDisplayNameInput('');\n setModelUrlInput(mode === HUAWEI_MAAS_ACCESS_MODAL_MODE ? HUAWEI_MAAS_ACCESS_URL : '');\n setModelApiKeyInput('');\n headerEditor.resetRows();\n }, [headerEditor]);\n\n const closeModal = useCallback(() => {\n setShowModal(false);\n setModalMode('default');\n setCreateError(null);\n setCreateModelSuccess(null);\n setEditingSourceId(null);\n setEditingOriginalModelName(null);\n setEditingSourceModels([]);\n setEditingModelBaseUrls({});\n setEditingModelDescriptions({});\n setEditingModelIcons({});\n headerEditor.clearErrors();\n }, [headerEditor]);\n\n const openModal = useCallback((mode: CreateModelModalMode = 'default') => {\n resetForm(mode);\n setModalMode(mode);\n setEditingSourceId(null);\n setEditingOriginalModelName(null);\n setEditingSourceModels([]);\n setEditingModelBaseUrls({});\n setEditingModelDescriptions({});\n setEditingModelIcons({});\n setCreateError(null);\n headerEditor.clearErrors();\n setCreateModelSuccess(null);\n setShowModal(true);\n }, [resetForm, headerEditor]);\n\n const openRiskModal = useCallback(() => {\n setShowRiskModal(true);\n }, []);\n\n const closeRiskModal = useCallback(() => {\n setShowRiskModal(false);\n }, []);\n\n const handleAgreeRisk = useCallback(() => {\n setShowRiskModal(false);\n openModal('default');\n }, [openModal]);\n\n const resolveDraftModelNames = useCallback(() => {\n if (!editingSourceId) return [modelNameInput.trim()].filter(Boolean);\n const nextModel = modelNameInput.trim();\n const previousModel = editingOriginalModelName?.trim() || '';\n const sourceModels =\n editingSourceModels.length > 0 ? [...editingSourceModels] : previousModel ? [previousModel] : [];\n const replacedModels = sourceModels.map((name) => (name === previousModel ? nextModel : name));\n return Array.from(\n new Set((replacedModels.length > 0 ? replacedModels : [nextModel]).map((name) => name.trim()).filter(Boolean)),\n );\n }, [editingSourceId, modelNameInput, editingOriginalModelName, editingSourceModels]);\n\n const handleCreateModel = useCallback(async () => {\n if (!canConfirm || saveModelBusy) return;\n\n const buildResult = buildHeadersObject(headerEditor.rows);\n if (buildResult.errorIndex !== null || buildResult.errorMessage) {\n headerEditor.setErrorRowIndex(buildResult.errorIndex);\n headerEditor.validateRows(headerEditor.rows);\n return;\n }\n headerEditor.setErrorRowIndex(null);\n\n setCreateError(null);\n setCreateModelSuccess(null);\n setSaveModelBusy(true);\n try {\n const description = modelDescriptionInput.trim();\n const displayName = modelDisplayNameInput.trim();\n const icon = modelIconInput.trim();\n const projectPath = resolveProjectPathForPayload();\n let method: 'POST' | 'PUT' = 'POST';\n let url = '/api/model-config-profiles';\n let payload: Record<string, unknown>;\n\n if (editingSourceId) {\n method = 'PUT';\n url = `/api/model-config-profiles/${encodeURIComponent(editingSourceId)}`;\n const mergedModels = resolveDraftModelNames();\n const previousModel = editingOriginalModelName?.trim() || '';\n const nextModel = modelNameInput.trim();\n const nextModelBaseUrls = Object.fromEntries(\n mergedModels\n .map((model) => {\n const baseUrl =\n model === nextModel\n ? modelUrlInput.trim() || editingModelBaseUrls[previousModel] || editingModelBaseUrls[model]\n : editingModelBaseUrls[model];\n return baseUrl ? ([model, baseUrl] as const) : null;\n })\n .filter((entry): entry is readonly [string, string] => entry !== null),\n );\n const nextModelDescriptions = { ...editingModelDescriptions };\n const nextModelIcons = { ...editingModelIcons };\n if (previousModel && previousModel !== nextModel) {\n delete nextModelDescriptions[previousModel];\n delete nextModelIcons[previousModel];\n }\n if (description) {\n nextModelDescriptions[nextModel] = description;\n } else {\n delete nextModelDescriptions[nextModel];\n }\n if (icon) {\n nextModelIcons[nextModel] = icon;\n } else {\n delete nextModelIcons[nextModel];\n }\n payload = {\n ...(displayName ? { displayName } : {}),\n ...(modelUrlInput.trim() ? { baseUrl: modelUrlInput.trim() } : {}),\n ...(modelApiKeyInput.trim() ? { apiKey: modelApiKeyInput.trim() } : {}),\n ...(buildResult.headers ? { headers: buildResult.headers } : {}),\n models: mergedModels,\n ...(Object.keys(nextModelBaseUrls).length > 0 ? { modelBaseUrls: nextModelBaseUrls } : {}),\n modelDescriptions: nextModelDescriptions,\n modelIcons: nextModelIcons,\n ...(projectPath ? { projectPath } : {}),\n };\n } else {\n payload = {\n sourceId: generateModelConfigSourceId(),\n ...(displayName ? { displayName } : {}),\n ...(description ? { description } : {}),\n ...(icon ? { icon } : {}),\n ...(isHuaweiMaasAccessMode ? { accessMode: HUAWEI_MAAS_ACCESS_MODE } : {}),\n baseUrl: modelUrlInput.trim(),\n apiKey: modelApiKeyInput.trim(),\n ...(buildResult.headers ? { headers: buildResult.headers } : {}),\n models: [modelNameInput.trim()],\n ...(projectPath ? { projectPath } : {}),\n };\n }\n\n const res = await apiFetch(url, {\n method,\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n });\n const body = (await res.json().catch(() => ({}))) as { error?: string };\n if (!res.ok) {\n throw new Error(body.error ?? `请求失败 (${res.status})`);\n }\n resetForm();\n closeModal();\n await fetchModels();\n } catch (error) {\n setCreateError(error instanceof Error ? error.message : String(error));\n } finally {\n setSaveModelBusy(false);\n }\n }, [\n canConfirm,\n saveModelBusy,\n headerEditor,\n modelDescriptionInput,\n modelDisplayNameInput,\n modelIconInput,\n modelUrlInput,\n modelApiKeyInput,\n editingSourceId,\n editingOriginalModelName,\n editingModelBaseUrls,\n editingModelDescriptions,\n editingModelIcons,\n resolveDraftModelNames,\n isHuaweiMaasAccessMode,\n modelNameInput,\n resolveProjectPathForPayload,\n resetForm,\n closeModal,\n fetchModels,\n ]);\n\n const handleTestConnection = useCallback(async () => {\n const url = modelUrlInput.trim();\n const apiKey = modelApiKeyInput.trim();\n const modelName = modelNameInput.trim();\n if (!url || !apiKey) return;\n\n setSaveModelBusy(true);\n setCreateError(null);\n setCreateModelSuccess(null);\n\n const showToast = useToastStore.getState().addToast;\n\n try {\n const res = await apiFetch('/api/maas-test-connection', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n suppressAuthRedirect: true,\n body: JSON.stringify({\n baseUrl: url,\n ...(apiKey && !(editingSourceId && apiKey.includes('****')) ? { apiKey } : {}),\n model: modelName || 'default',\n ...(editingSourceId ? { sourceId: editingSourceId } : {}),\n ...(resolveProjectPathForPayload() ? { projectPath: resolveProjectPathForPayload() } : {}),\n }),\n });\n\n const body = (await res.json().catch(() => ({}))) as { error?: string; success?: boolean };\n if (!res.ok || body.error) {\n throw new Error(body.error ?? `HTTP ${res.status}`);\n }\n\n showToast({ type: 'success', title: '测试连接成功', message: '连接测试成功', duration: 3000 });\n } catch {\n showToast({\n type: 'error',\n title: '测试连接失败',\n message: '请检查模型调用名称或者API Key填写是否正确',\n duration: 5000,\n });\n } finally {\n setSaveModelBusy(false);\n }\n }, [modelUrlInput, modelApiKeyInput, modelNameInput, editingSourceId, resolveProjectPathForPayload]);\n\n const handleOpenEditModelModal = useCallback(async (card: ModelCardData) => {\n const sourceId = resolveModelConfigSourceId(card.id);\n if (!sourceId || editModelBusy) return;\n\n resetForm('default');\n setModalMode(card.accessMode === HUAWEI_MAAS_ACCESS_MODE || card.baseUrl?.includes('modelarts-maas') ? HUAWEI_MAAS_ACCESS_MODAL_MODE : 'default');\n setCreateError(null);\n setCreateModelSuccess(null);\n setEditModelBusy(true);\n headerEditor.clearErrors();\n\n try {\n const projectPath = resolveProjectPathForPayload();\n const query = new URLSearchParams();\n if (projectPath) query.set('projectPath', projectPath);\n const queryText = query.toString();\n const apiUrl = `/api/model-config-profiles${queryText ? `?${queryText}` : ''}`;\n const res = await apiFetch(apiUrl);\n const body = (await res.json().catch(() => ({}))) as { providers?: ModelConfigProviderItem[]; error?: string };\n if (!res.ok) {\n throw new Error(body.error ?? `请求失败 (${res.status})`);\n }\n const provider = (body.providers ?? []).find((item) => item.id === sourceId);\n\n setEditingSourceId(sourceId);\n setEditingOriginalModelName(card.name);\n setEditingSourceModels(Array.isArray(provider?.models) ? provider.models : [card.name]);\n setEditingModelBaseUrls(provider?.modelBaseUrls ?? {});\n setEditingModelDescriptions(provider?.modelDescriptions ?? {});\n setEditingModelIcons(provider?.modelIcons ?? {});\n setModelNameInput(card.name);\n setModelDescriptionInput(provider?.modelDescriptions?.[card.name] ?? card.description ?? provider?.description ?? '');\n setModelDisplayNameInput(provider?.displayName ?? '');\n setModelIconInput(provider?.modelIcons?.[card.name]?.trim() || provider?.icon?.trim() || card.icon?.trim() || '');\n setModelUrlInput(provider?.modelBaseUrls?.[card.name] ?? card.baseUrl ?? provider?.baseUrl ?? '');\n setModelApiKeyInput(provider?.apiKey ?? '');\n headerEditor.setRowsFromHeaders(provider?.headers);\n setShowModal(true);\n } catch (error) {\n setCreateError(error instanceof Error ? error.message : String(error));\n } finally {\n setEditModelBusy(false);\n }\n }, [editModelBusy, resetForm, headerEditor, resolveProjectPathForPayload]);\n\n return {\n showModal,\n openModal,\n closeModal,\n modalMode,\n\n modelNameInput,\n setModelNameInput,\n modelDescriptionInput,\n setModelDescriptionInput,\n modelIconInput,\n setModelIconInput,\n modelDisplayNameInput,\n setModelDisplayNameInput,\n modelUrlInput,\n setModelUrlInput,\n modelApiKeyInput,\n setModelApiKeyInput,\n\n headerRows: headerEditor.rows,\n headerRowErrors: headerEditor.rowErrors,\n headerErrorRowIndex: headerEditor.errorRowIndex,\n handleAddHeaderRow: headerEditor.handleAddRow,\n handleHeaderRowChange: headerEditor.handleRowChange,\n handleRemoveHeaderRow: headerEditor.handleRemoveRow,\n\n isModelNameValid,\n showModelNameValidationError,\n canConfirm,\n\n isEditMode,\n editingSourceId,\n editingOriginalModelName,\n editingSourceModels,\n editModelBusy,\n handleOpenEditModelModal,\n\n createError,\n createModelSuccess,\n saveModelBusy,\n handleCreateModel,\n handleTestConnection,\n\n showRiskModal,\n openRiskModal,\n closeRiskModal,\n handleAgreeRisk,\n\n resolveProjectPathForPayload,\n };\n}\n\n// Helper function (imported from utils but needs local binding for edit modal)\nfunction resolveModelConfigSourceId(cardId: string): string | null {\n if (!cardId.startsWith('model_config:')) return null;\n const parts = cardId.split(':');\n if (parts.length < 3) return null;\n const sourceId = parts[1]?.trim();\n return sourceId ? sourceId : null;\n}\n","/*\n * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n */\n\nimport { useCallback, useState } from 'react';\nimport { apiFetch } from '@/utils/api-client';\nimport { generateModelConfigSourceId, parseHeadersJson, SAVE_MODEL_LABEL } from '../utils';\n\nexport interface UseAddModelFormResult {\n // Form fields\n sourceId: string;\n displayName: string;\n baseUrl: string;\n apiKey: string;\n headersText: string;\n models: string[];\n\n // Actions\n setDisplayName: (value: string) => void;\n setBaseUrl: (value: string) => void;\n setApiKey: (value: string) => void;\n setHeadersText: (value: string) => void;\n setModels: (value: string[]) => void;\n\n // Status\n canCreate: boolean;\n saveBusy: boolean;\n error: string | null;\n successMessage: string | null;\n\n // Operations\n handleSave: () => Promise<void>;\n reset: () => void;\n}\n\nexport function useAddModelForm(\n projectPath: string | null,\n onCreated: () => Promise<void>,\n onError: (error: string | null) => void,\n): UseAddModelFormResult {\n const [sourceId, setSourceId] = useState(() => generateModelConfigSourceId());\n const [displayName, setDisplayName] = useState('');\n const [baseUrl, setBaseUrl] = useState('');\n const [apiKey, setApiKey] = useState('');\n const [headersText, setHeadersText] = useState('');\n const [models, setModels] = useState<string[]>([]);\n const [saveBusy, setSaveBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [successMessage, setSuccessMessage] = useState<string | null>(null);\n\n const canCreate =\n displayName.trim().length > 0 && baseUrl.trim().length > 0 && apiKey.trim().length > 0 && models.length > 0;\n\n const reset = useCallback(() => {\n setSourceId(generateModelConfigSourceId());\n setDisplayName('');\n setBaseUrl('');\n setApiKey('');\n setHeadersText('');\n setModels([]);\n setError(null);\n setSuccessMessage(null);\n }, []);\n\n const handleSave = useCallback(async () => {\n onError(null);\n setSuccessMessage(null);\n setSaveBusy(true);\n try {\n const headers = parseHeadersJson(headersText);\n const res = await apiFetch('/api/model-config-profiles', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n ...(projectPath ? { projectPath } : {}),\n sourceId: sourceId.trim(),\n displayName: displayName.trim(),\n baseUrl: baseUrl.trim(),\n apiKey: apiKey.trim(),\n ...(headers ? { headers } : {}),\n models,\n }),\n });\n const body = (await res.json().catch(() => ({}))) as { error?: string };\n if (!res.ok) {\n throw new Error(body.error ?? `请求失败 (${res.status})`);\n }\n reset();\n await onCreated();\n } catch (saveError) {\n const errorMessage = saveError instanceof Error ? saveError.message : String(saveError);\n setError(errorMessage);\n onError(errorMessage);\n } finally {\n setSaveBusy(false);\n }\n }, [projectPath, sourceId, displayName, baseUrl, apiKey, headersText, models, reset, onCreated, onError]);\n\n return {\n sourceId,\n displayName,\n baseUrl,\n apiKey,\n headersText,\n models,\n setDisplayName,\n setBaseUrl,\n setApiKey,\n setHeadersText,\n setModels,\n canCreate,\n saveBusy,\n error,\n successMessage,\n handleSave,\n reset,\n };\n}","/*\n * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n */\n\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport { useChatStore } from '@/stores/chatStore';\nimport { useToastStore } from '@/stores/toastStore';\nimport { apiFetch } from '@/utils/api-client';\nimport { readPublicEnv } from '@/utils/client-env';\nimport {\n DEFAULT_MAAS_API_KEY_URL,\n HUAWEI_MAAS_SERVICE_CONFIGS,\n resolveHuaweiMaasServiceType,\n resolveHuaweiMaasAccessModelIds,\n} from '../utils';\nimport type { HuaweiMaasServiceType } from '../utils';\nimport type { ModelConfigProviderItem } from '../types/models-panel';\n\ntype ProviderByService = Partial<Record<HuaweiMaasServiceType, ModelConfigProviderItem>>;\n\nexport interface UseHuaweiMaasAccessFormResult {\n activeServiceType: HuaweiMaasServiceType;\n setActiveServiceType: (value: HuaweiMaasServiceType) => void;\n apiKey: string;\n setApiKey: (value: string) => void;\n loading: boolean;\n saving: boolean;\n canConfirm: boolean;\n activeHasApiKey: boolean;\n updatingApiKey: boolean;\n apiKeyUrl: string;\n startApiKeyUpdate: () => void;\n handleConfirm: () => Promise<void>;\n}\n\nexport function useHuaweiMaasAccessForm(\n open: boolean,\n onClose: () => void,\n onSaved: () => Promise<void>,\n): UseHuaweiMaasAccessFormResult {\n const currentProjectPath = useChatStore((s) => s.currentProjectPath);\n const [activeServiceType, setActiveServiceType] = useState<HuaweiMaasServiceType>('claw-plan');\n const [apiKey, setApiKey] = useState('');\n const [providersByService, setProvidersByService] = useState<ProviderByService>({});\n const [loading, setLoading] = useState(false);\n const [saving, setSaving] = useState(false);\n const [updatingApiKey, setUpdatingApiKey] = useState(false);\n\n const projectPath = currentProjectPath && currentProjectPath !== 'default' ? currentProjectPath : undefined;\n const existingApiKey =\n providersByService[activeServiceType]?.apiKey ||\n providersByService['claw-plan']?.apiKey ||\n providersByService.maas?.apiKey ||\n '';\n const activeHasApiKey = existingApiKey.trim().length > 0;\n const canConfirm = ((activeHasApiKey && !updatingApiKey) || apiKey.trim().length > 0) && !loading && !saving;\n const apiKeyUrl = readPublicEnv('PUBLIC_MAAS_API_KEY_URL')?.trim() || DEFAULT_MAAS_API_KEY_URL;\n\n const profilesUrl = useMemo(() => {\n if (!projectPath) return '/api/model-config-profiles';\n const query = new URLSearchParams({ projectPath });\n return `/api/model-config-profiles?${query.toString()}`;\n }, [projectPath]);\n\n const loadProfiles = useCallback(async () => {\n setLoading(true);\n try {\n const res = await apiFetch(profilesUrl);\n const body = (await res.json().catch(() => ({}))) as {\n providers?: ModelConfigProviderItem[];\n };\n if (!res.ok) {\n setProvidersByService({});\n return;\n }\n\n const nextProviders: ProviderByService = {};\n for (const provider of body.providers ?? []) {\n const serviceType = resolveHuaweiMaasServiceType(provider);\n if (serviceType && !nextProviders[serviceType]) {\n nextProviders[serviceType] = provider;\n }\n }\n setProvidersByService(nextProviders);\n\n const sharedApiKey = nextProviders['claw-plan']?.apiKey || nextProviders.maas?.apiKey || '';\n if (sharedApiKey) {\n setApiKey(sharedApiKey);\n }\n } finally {\n setLoading(false);\n }\n }, [profilesUrl]);\n\n useEffect(() => {\n if (!open) return;\n void loadProfiles();\n }, [open, loadProfiles]);\n\n useEffect(() => {\n if (!open || updatingApiKey || !existingApiKey) return;\n setApiKey(existingApiKey);\n }, [existingApiKey, open, updatingApiKey]);\n\n useEffect(() => {\n if (open) return;\n setActiveServiceType('claw-plan');\n setApiKey('');\n setProvidersByService({});\n setUpdatingApiKey(false);\n }, [open]);\n\n const startApiKeyUpdate = useCallback(() => {\n setUpdatingApiKey(true);\n setApiKey('');\n }, []);\n\n const handleConfirm = useCallback(async () => {\n if (activeHasApiKey && !updatingApiKey) {\n onClose();\n return;\n }\n\n const trimmedApiKey = apiKey.trim();\n if (!trimmedApiKey || saving) return;\n\n const config = HUAWEI_MAAS_SERVICE_CONFIGS[activeServiceType];\n const provider = providersByService[activeServiceType];\n setSaving(true);\n\n try {\n let models: string[];\n let modelBaseUrls: Record<string, string> | undefined;\n if (activeServiceType === 'maas') {\n const res = await apiFetch('/api/maas-models-query', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ baseUrl: config.baseUrl, apiKey: trimmedApiKey }),\n });\n const body = (await res.json().catch(() => ({}))) as {\n models?: Array<{ id?: string; baseUrl?: string }>;\n error?: string;\n };\n if (!res.ok) {\n throw new Error(body.error ?? `查询已购模型失败 (${res.status})`);\n }\n models = Array.isArray(body.models)\n ? body.models\n .map((item) => (typeof item?.id === 'string' ? item.id.trim() : ''))\n .filter((id): id is string => id.length > 0)\n : [];\n const baseUrlEntries = (body.models ?? [])\n .map((item) => {\n const id = typeof item?.id === 'string' ? item.id.trim() : '';\n const baseUrl = typeof item?.baseUrl === 'string' ? item.baseUrl.trim() : '';\n return id && baseUrl ? ([id, baseUrl] as const) : null;\n })\n .filter((entry): entry is readonly [string, string] => entry !== null);\n if (baseUrlEntries.length > 0) {\n modelBaseUrls = Object.fromEntries(baseUrlEntries);\n }\n if (models.length === 0) {\n throw new Error('未查询到已购模型,请确认 API Key 是否正确或是否已购买模型。');\n }\n } else {\n models = resolveHuaweiMaasAccessModelIds(\n activeServiceType,\n readPublicEnv('PUBLIC_CLAW_PLAN_MODELS')?.trim(),\n );\n }\n\n const sourceId = provider?.id || config.sourceId;\n const basePayload = {\n displayName: config.displayName,\n baseUrl: config.baseUrl,\n apiKey: trimmedApiKey,\n serviceType: activeServiceType,\n ...(models.length > 0 ? { models } : {}),\n ...(modelBaseUrls ? { modelBaseUrls } : {}),\n ...(projectPath ? { projectPath } : {}),\n };\n const isUpdate = Boolean(provider?.id);\n const url = isUpdate\n ? `/api/model-config-profiles/${encodeURIComponent(sourceId)}`\n : '/api/model-config-profiles';\n const res = await apiFetch(url, {\n method: isUpdate ? 'PUT' : 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(isUpdate ? basePayload : { ...basePayload, sourceId }),\n });\n const body = (await res.json().catch(() => ({}))) as { error?: string };\n if (!res.ok) {\n throw new Error(body.error ?? `请求失败 (${res.status})`);\n }\n\n useToastStore.getState().addToast({\n type: 'success',\n title: '模型接入成功。',\n message: '模型接入成功。',\n duration: 3000,\n });\n setUpdatingApiKey(false);\n onClose();\n await onSaved();\n } catch {\n useToastStore.getState().addToast({\n type: 'error',\n title: '模型接入失败,请核对接入信息后重试。',\n message: '模型接入失败,请核对接入信息后重试。',\n duration: 5000,\n });\n } finally {\n setSaving(false);\n }\n }, [activeHasApiKey, activeServiceType, apiKey, onClose, onSaved, projectPath, providersByService, saving, updatingApiKey]);\n\n return {\n activeServiceType,\n setActiveServiceType,\n apiKey,\n setApiKey,\n loading,\n saving,\n canConfirm,\n activeHasApiKey,\n updatingApiKey,\n apiKeyUrl,\n startApiKeyUpdate,\n handleConfirm,\n };\n}\n","/*\n * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n */\n\nimport { MaskIcon } from '@/components/shared/MaskIcon';\nimport { SearchInput } from '@/components/shared/SearchInput';\nimport { Button } from '@/components/shared/Button';\nimport { useChatStore } from '@/stores/chatStore';\nimport {\n CREATE_MODEL_LABEL,\n HUAWEI_MAAS_ACCESS_LABEL,\n MODEL_TITLE,\n SEARCH_PLACEHOLDER,\n} from '../utils';\n\nexport interface ModelsToolbarProps {\n loading: boolean;\n isSkipAuth: boolean;\n canCreateModel: boolean;\n searchQuery: string;\n onSearchChange: (query: string) => void;\n onRefresh: () => void;\n onOpenCreateModel: () => void;\n onOpenHuaweiMaasAccess: () => void;\n}\n\nexport function ModelsToolbar({\n loading,\n isSkipAuth,\n canCreateModel,\n searchQuery,\n onSearchChange,\n onRefresh,\n onOpenCreateModel,\n onOpenHuaweiMaasAccess,\n}: ModelsToolbarProps) {\n const openHub = useChatStore((s) => s.openHub);\n\n return (\n <>\n <div className=\"ui-page-header-inline mb-4\">\n <h1 className=\"ui-page-title\">{MODEL_TITLE}</h1>\n <div className=\"flex items-center justify-end gap-2\">\n <button\n type=\"button\"\n onClick={() => openHub('provider-profiles')}\n className=\"hidden rounded-[16px] border border-[var(--button-default-border)] bg-[var(--button-default-bg)] px-3 py-1.5 text-[12px] font-medium text-[var(--button-default-text)] transition-colors hover:border-[var(--button-default-border-hover)] hover:bg-[var(--button-default-bg-hover)] hover:text-[var(--button-default-text-hover)]\"\n >\n ACP / 账号配置\n </button>\n {!isSkipAuth ? (\n <Button variant=\"major\"\n onClick={onOpenHuaweiMaasAccess}\n data-testid=\"models-open-huawei-maas-model-modal\"\n >\n {HUAWEI_MAAS_ACCESS_LABEL}\n </Button>\n ) : null}\n {canCreateModel ? (\n <Button variant=\"major\"\n onClick={onOpenCreateModel}\n data-testid=\"models-open-create-model-modal\"\n >\n {CREATE_MODEL_LABEL}\n </Button>\n ) : null}\n </div>\n </div>\n\n <section className=\"shrink-0 pb-6\" data-testid=\"models-toolbar\">\n <div className=\"flex items-center gap-2\">\n <SearchInput\n wrapperClassName=\"flex-1\"\n aria-label=\"搜索模型\"\n value={searchQuery}\n onChange={onSearchChange}\n onClear={() => onSearchChange('')}\n placeholder={SEARCH_PLACEHOLDER}\n clearAriaLabel=\"清除搜索\"\n />\n <button\n type=\"button\"\n aria-label=\"刷新\"\n title=\"刷新\"\n data-testid=\"models-refresh-button\"\n onClick={onRefresh}\n disabled={loading}\n className=\"inline-flex h-[28px] w-[28px] shrink-0 items-center justify-center rounded-[8px] border border-[var(--border-default)] bg-[var(--surface-panel)] text-[var(--text-secondary)] transition-colors hover:bg-[var(--surface-hover)] hover:text-[var(--text-primary)] disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <MaskIcon name=\"refresh\" className=\"h-4 w-4\" />\n </button>\n </div>\n </section>\n </>\n );\n}","/*\n * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n */\n\nimport { NameInitialIcon } from '@/components/NameInitialIcon';\nimport { OverflowTooltip } from '@/components/shared/OverflowTooltip';\nimport { formatCustomModelUpdatedAt, resolveUploadedIconUrl, VENDOR_ICON, HUAWEI_MAAS_PROTOCOL, HUAWEI_MAAS_GROUP_KEY } from '../utils';\nimport type { ModelCardData } from '../types/models-panel';\n\nfunction ClockIcon() {\n return (\n <svg className=\"h-4 w-4 shrink-0\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n <circle cx=\"12\" cy=\"12\" r=\"8\" stroke=\"currentColor\" strokeWidth=\"1.8\" />\n <path d=\"M12 7.5V12L15 13.8\" stroke=\"currentColor\" strokeWidth=\"1.8\" strokeLinecap=\"round\" />\n </svg>\n );\n}\n\nexport interface ModelCardProps {\n card: ModelCardData;\n groupKey: string;\n deletingModelId: string | null;\n editModelBusy: boolean;\n onEdit: (card: ModelCardData) => void;\n onDelete: (cardId: string, cardName: string) => void;\n}\n\nexport function ModelCard({ card, groupKey, deletingModelId, editModelBusy, onEdit, onDelete }: ModelCardProps) {\n const cardIconSrc = resolveUploadedIconUrl(card.icon);\n const customModelUpdatedAt = card.protocol !== HUAWEI_MAAS_PROTOCOL ? formatCustomModelUpdatedAt(card.updatedAt) : null;\n\n return (\n <article\n className={[\n 'ui-card',\n groupKey === HUAWEI_MAAS_GROUP_KEY ? null : 'ui-card-hover',\n 'group flex min-h-[194px] flex-col gap-4',\n ]\n .filter(Boolean)\n .join(' ')}\n >\n <div>\n <div className=\"flex items-start gap-3\">\n {cardIconSrc ? (\n // eslint-disable-next-line @next/next/no-img-element\n <img\n src={cardIconSrc}\n alt={`${card.name} icon`}\n width={48}\n height={48}\n className=\"h-12 w-12 shrink-0 rounded-[var(radius-xs)] object-cover\"\n data-testid={`model-card-icon-${card.id}`}\n />\n ) : (\n <div className=\"h-12 w-12 shrink-0 rounded-[var(radius-xs)]\">\n <NameInitialIcon\n name={card.name}\n dataTestId={`model-card-icon-${card.id}`}\n className=\"h-full w-full rounded-[var(--radius-md)] border-0 shadow-none\"\n />\n </div>\n )}\n\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-start justify-between gap-2\">\n <OverflowTooltip\n content={card.name}\n className=\"min-w-0 flex-1\"\n as=\"h4\"\n textClassName=\"block truncate text-[var(--font-size-xl)] font-semibold text-[var(--text-primary)]\"\n />\n </div>\n {card.labels.length > 0 ? (\n <div className=\"mt-1 flex flex-wrap items-center gap-1.5\">\n {card.labels.map((label, index) => (\n <span key={`${card.id}-label-${label}-${index}`} className=\"ui-badge-muted\">\n {label}\n </span>\n ))}\n </div>\n ) : null}\n </div>\n </div>\n </div>\n\n <OverflowTooltip content={card.description} className=\"w-full\">\n <p className=\"text-[14px] min-h-[44px] leading-[22px] text-[var(--text-secondary)] line-clamp-2 break-all overflow-hidden\">\n {card.description || card.name}\n </p>\n </OverflowTooltip>\n\n <div className=\"flex items-end justify-between gap-3\">\n <div className=\"min-h-5 text-xs leading-[24px]\">\n {card.protocol !== HUAWEI_MAAS_PROTOCOL ? (\n <div className=\"relative\">\n <span className=\"inline-flex items-center gap-1.5 text-[var(--text-muted)] transition-opacity duration-200 group-hover:opacity-0\">\n {customModelUpdatedAt ? (\n <>\n <span\n className=\"inline-flex h-4 w-4 items-center justify-center\"\n data-testid={`model-card-updated-at-icon-${card.id}`}\n >\n <ClockIcon />\n </span>\n <span data-testid={`model-card-updated-at-${card.id}`}>\n {customModelUpdatedAt}\n </span>\n </>\n ) : (\n <>\n {/* eslint-disable-next-line @next/next/no-img-element */}\n <img\n src={VENDOR_ICON}\n alt={`${card.developer} icon`}\n width={16}\n height={16}\n className=\"h-4 w-4 rounded-sm object-cover\"\n />\n <span>{card.developer}</span>\n </>\n )}\n </span>\n <div className=\"absolute left-0 top-0 flex items-center whitespace-nowrap opacity-0 transition-opacity duration-200 group-hover:opacity-100\">\n <button\n type=\"button\"\n data-testid={`model-card-edit-${card.id}`}\n disabled={editModelBusy}\n onClick={() => onEdit(card)}\n className=\"whitespace-nowrap text-[14px] font-bold leading-[24px] text-[var(--text-accent)] hover:underline hover:underline-offset-2 disabled:opacity-50\"\n style={{ textUnderlineOffset: '4px' }}\n >\n 编辑\n </button>\n <button\n type=\"button\"\n disabled={deletingModelId === card.id}\n onClick={() => onDelete(card.id, card.name)}\n data-testid={`model-card-delete-${card.id}`}\n className=\"ml-[24px] whitespace-nowrap text-[14px] font-bold leading-[24px] text-[var(--text-accent)] hover:underline hover:underline-offset-2 disabled:opacity-50\"\n style={{ textUnderlineOffset: '4px' }}\n >\n {deletingModelId === card.id ? '删除中...' : '删除'}\n </button>\n </div>\n </div>\n ) : (\n <span className=\"inline-flex items-center gap-1.5 text-[var(--text-muted)]\">\n {/* eslint-disable-next-line @next/next/no-img-element */}\n <img\n src={VENDOR_ICON}\n alt={`${card.developer} icon`}\n width={16}\n height={16}\n className=\"h-4 w-4 rounded-sm object-cover\"\n />\n <span>{card.developer}</span>\n </span>\n )}\n </div>\n </div>\n </article>\n );\n}","/*\n * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n */\n\nimport { ModelCard } from './ModelCard';\nimport type { ModelCardData, ModelCardGroup } from '../types/models-panel';\n\nexport interface ModelGroupSectionProps {\n group: ModelCardGroup;\n deletingModelId: string | null;\n editModelBusy: boolean;\n onEdit: (card: ModelCardData) => void;\n onDelete: (cardId: string, cardName: string) => void;\n}\n\nexport function ModelGroupSection({ group, deletingModelId, editModelBusy, onEdit, onDelete }: ModelGroupSectionProps) {\n return (\n <section className=\"space-y-3\">\n <h3 className=\"text-[14px] font-semibold text-[var(--text-primary)] mb-4\">\n {group.label} ({group.items.length})\n </h3>\n\n <div className=\"grid grid-cols-1 gap-3 md:grid-cols-2 xl:grid-cols-3\">\n {group.items.map((card) => (\n <ModelCard\n key={card.id}\n card={card}\n groupKey={group.key}\n deletingModelId={deletingModelId}\n editModelBusy={editModelBusy}\n onEdit={onEdit}\n onDelete={onDelete}\n />\n ))}\n </div>\n </section>\n );\n}","/*\n * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n */\n\nimport { type ChangeEvent, useEffect, useRef, useState } from 'react';\nimport { MaskIcon } from '@/components/shared/MaskIcon';\nimport { Button } from '@/components/shared/Button';\nimport { PasswordField } from '@/components/shared/PasswordField';\nimport { Textarea } from '@/components/shared/Textarea';\nimport { useToastStore } from '@/stores/toastStore';\nimport { uploadAvatarAsset } from '@/components/hub-agent-editor.client';\nimport { buildNameInitialIconDataUrl } from '@/lib/name-initial-icon';\nimport {\n CREATE_MODEL_CANCEL_LABEL,\n DEFAULT_MODEL_ICON_SRC,\n MODEL_ICON_MAX_BYTES,\n MODEL_NAME_VALIDATION_MESSAGE,\n SAVE_MODEL_LABEL,\n TEST_CONNECTION_LABEL,\n HUAWEI_MAAS_ACCESS_LABEL,\n CREATE_MODEL_LABEL,\n HUAWEI_MAAS_ACCESS_MODAL_MODE,\n resolveUploadedIconUrl,\n} from '../utils';\nimport type { CreateModelModalMode, HeaderInputRow } from '../types/models-panel';\n\nfunction CloseIcon() {\n return <MaskIcon name=\"close\" className=\"h-4 w-4\" />;\n}\n\nexport interface CreateModelModalProps {\n show: boolean;\n onClose: () => void;\n modalMode: CreateModelModalMode;\n isEditMode: boolean;\n\n // Form fields\n modelNameInput: string;\n onModelNameChange: (value: string) => void;\n modelDescriptionInput: string;\n onModelDescriptionChange: (value: string) => void;\n modelIconInput: string;\n onModelIconChange: (value: string) => void;\n modelDisplayNameInput: string;\n onModelDisplayNameChange: (value: string) => void;\n modelUrlInput: string;\n onModelUrlChange: (value: string) => void;\n modelApiKeyInput: string;\n onModelApiKeyChange: (value: string) => void;\n\n // Header rows\n headerRows: HeaderInputRow[];\n headerRowErrors: Map<string, { keyError?: string; valueError?: string }>;\n headerErrorRowIndex: number | null;\n onAddHeaderRow: () => void;\n onHeaderRowChange: (rowId: string, field: 'key' | 'value', value: string) => void;\n onRemoveHeaderRow: (rowId: string) => void;\n\n // Validation\n isModelNameValid: boolean;\n showModelNameValidationError: boolean;\n canConfirm: boolean;\n\n // Actions\n createError: string | null;\n saveModelBusy: boolean;\n testingConnection: boolean;\n editModelBusy: boolean;\n onCreate: () => void;\n onTestConnection: () => void;\n}\n\nexport function CreateModelModal({\n show,\n onClose,\n modalMode,\n isEditMode,\n modelNameInput,\n onModelNameChange,\n modelDescriptionInput,\n onModelDescriptionChange,\n modelIconInput,\n onModelIconChange,\n modelDisplayNameInput,\n onModelDisplayNameChange,\n modelUrlInput,\n onModelUrlChange,\n modelApiKeyInput,\n onModelApiKeyChange,\n headerRows,\n headerRowErrors,\n headerErrorRowIndex,\n onAddHeaderRow,\n onHeaderRowChange,\n onRemoveHeaderRow,\n // isModelNameValid - not used in render\n showModelNameValidationError,\n canConfirm,\n createError,\n saveModelBusy,\n testingConnection,\n editModelBusy,\n onCreate,\n onTestConnection,\n}: CreateModelModalProps) {\n const modelIconFileInputRef = useRef<HTMLInputElement | null>(null);\n const [isIconUploading, setIsIconUploading] = useState(false);\n const isHuaweiMaasAccessMode = modalMode === HUAWEI_MAAS_ACCESS_MODAL_MODE;\n const modelIconPreviewSrc = resolveUploadedIconUrl(modelIconInput) ?? DEFAULT_MODEL_ICON_SRC;\n\n // Scroll to first header row error when validation fails\n useEffect(() => {\n if (headerErrorRowIndex !== null) {\n const errorRow = document.querySelector('[data-error-row=\"true\"]');\n errorRow?.scrollIntoView({ behavior: 'smooth', block: 'center' });\n }\n }, [headerErrorRowIndex]);\n\n const handleModelIconUpload = async (event: ChangeEvent<HTMLInputElement>) => {\n const file = event.target.files?.[0];\n if (!file) return;\n\n const allowedTypes = ['image/png', 'image/jpeg', 'image/jpg'];\n if (!allowedTypes.includes(file.type)) {\n useToastStore.getState().addToast({\n type: 'error',\n title: '图标格式不支持',\n message: '仅支持 png、jpeg、jpg 格式图片',\n duration: 3000,\n });\n event.target.value = '';\n return;\n }\n\n if (file.size > MODEL_ICON_MAX_BYTES) {\n useToastStore.getState().addToast({\n type: 'error',\n title: '图标文件过大',\n message: '图片大小不能超过 200KB',\n duration: 3000,\n });\n event.target.value = '';\n return;\n }\n\n setIsIconUploading(true);\n try {\n const uploaded = await uploadAvatarAsset(file);\n onModelIconChange(uploaded);\n } catch (error) {\n useToastStore.getState().addToast({\n type: 'error',\n title: '图标上传失败',\n message: error instanceof Error ? error.message : '图标上传失败',\n duration: 3000,\n });\n } finally {\n setIsIconUploading(false);\n event.target.value = '';\n }\n };\n\n if (!show) return null;\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-[var(--overlay-backdrop-strong)] p-4\"\n data-testid=\"models-create-model-modal\"\n >\n <div className=\"relative flex w-[500px] max-h-[calc(100vh-4rem)] flex-col gap-5 overflow-hidden rounded-[8px] border border-[var(--modal-border)] bg-[var(--modal-surface)] p-6 shadow-[var(--modal-shadow)]\">\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"close\"\n className=\"absolute right-5 top-5 flex h-6 w-6 items-center justify-center rounded text-[var(--modal-close-icon)] transition-colors hover:bg-[var(--modal-close-hover-bg)] hover:text-[var(--modal-close-icon-hover)]\"\n >\n <CloseIcon />\n </button>\n <div className=\"pr-10\">\n <h3 className=\"text-[16px] font-bold text-[var(--modal-title-text)]\">\n {isEditMode ? '编辑' : isHuaweiMaasAccessMode ? HUAWEI_MAAS_ACCESS_LABEL : CREATE_MODEL_LABEL}\n </h3>\n </div>\n\n <div className=\"min-h-0 flex-1 space-y-4 overflow-y-auto pr-1\">\n <div className=\"space-y-1\">\n <p className=\"text-[12px] leading-[18px] text-[var(--modal-text)]\">\n {isHuaweiMaasAccessMode ? '模型调用名称' : '模型名称'}\n </p>\n <input\n data-testid=\"models-create-model-name-input\"\n value={modelNameInput}\n onChange={(event) => onModelNameChange(event.target.value)}\n placeholder={isHuaweiMaasAccessMode ? '请输入模型调用名称' : '请输入模型名称'}\n className=\"ui-input w-full\"\n style={{ height: '28px' }}\n required\n />\n {showModelNameValidationError ? (\n <p\n data-testid=\"models-create-model-name-error\"\n className=\"mt-1 text-xs text-[var(--state-error-text)]\"\n >\n {MODEL_NAME_VALIDATION_MESSAGE}\n </p>\n ) : null}\n </div>\n\n <div className=\"space-y-2.5\">\n <div className=\"text-[12px] text-[var(--text-primary)]\">模型描述(可选)</div>\n <Textarea\n data-testid=\"models-create-model-description-textarea\"\n value={modelDescriptionInput}\n onChange={(event) => onModelDescriptionChange(event.target.value)}\n placeholder=\"请输入描述\"\n maxLength={500}\n showCount\n formatCount={(current, max) => `${current}/${max ?? 0}`}\n className=\"h-[60px] min-h-[60px] w-full\"\n />\n </div>\n\n <div className=\"hidden space-y-1\">\n <p className=\"text-[12px] leading-[18px] text-[var(--modal-text)]\">模型展示名称</p>\n <input\n data-testid=\"models-create-model-display-name-input\"\n value={modelDisplayNameInput}\n onChange={(event) => onModelDisplayNameChange(event.target.value)}\n placeholder=\"请输入模型展示名称\"\n className=\"ui-input w-full\"\n style={{ height: '28px' }}\n required\n />\n </div>\n\n <div className=\"space-y-2.5\">\n <div className=\"text-[12px] text-[var(--text-primary)]\">图标(可选)</div>\n <div className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n aria-label=\"Upload model icon\"\n onClick={() => modelIconFileInputRef.current?.click()}\n className=\"group relative flex h-11 w-11 items-center justify-center rounded-[var(--radius-xs)] transition overflow-hidden\"\n >\n {/* eslint-disable-next-line @next/next/no-img-element */}\n <img src={modelIconPreviewSrc} alt=\"Model icon preview\" className=\"h-full w-full object-cover\" />\n <span className=\"pointer-events-none absolute inset-0 flex items-center justify-center bg-[var(--modal-loading-overlay)] opacity-0 transition group-hover:opacity-100\">\n <MaskIcon name=\"edit\" preserveOriginalColor className=\"h-4 w-4\" />\n </span>\n </button>\n <input\n ref={modelIconFileInputRef}\n type=\"file\"\n accept=\"image/png,image/jpeg,image/jpg\"\n onChange={handleModelIconUpload}\n className=\"hidden\"\n data-testid=\"models-create-model-icon-file-input\"\n />\n <div className=\"h-11 pt-[22px]\">\n <div aria-hidden=\"true\" className=\"h-[16px] w-px bg-[var(--border-default)]\" />\n </div>\n <div className=\"h-11 pt-[16px]\">\n <button\n type=\"button\"\n aria-label=\"Random model icon\"\n onClick={() => {\n const nextVariant = Math.floor(Math.random() * 10_000);\n onModelIconChange(buildNameInitialIconDataUrl(modelNameInput, nextVariant));\n }}\n className=\"h-[28px] w-[28px] min-h-[28px] min-w-[28px] p-0\"\n >\n <MaskIcon name=\"random\" />\n </button>\n </div>\n </div>\n <div className=\"text-[12px] text-[var(--text-muted)]\">\n {isIconUploading ? '图标上传中...' : '支持上传 png、jpeg、jpg 格式图片,限制 200KB 内'}\n </div>\n </div>\n\n <div className=\"space-y-1\">\n <p className=\"text-[12px] leading-[18px] text-[var(--modal-text)]\">访问URL</p>\n <input\n data-testid=\"models-create-model-url-input\"\n name=\"cc_model_base_url\"\n value={modelUrlInput}\n onChange={(event) => onModelUrlChange(event.target.value)}\n placeholder=\"请输入访问URL\"\n autoComplete=\"off\"\n autoCorrect=\"off\"\n autoCapitalize=\"off\"\n spellCheck={false}\n disabled={isHuaweiMaasAccessMode}\n className={`ui-input w-full ${\n isHuaweiMaasAccessMode\n ? 'cursor-not-allowed border-[var(--overlay-disabled-border)] bg-[var(--overlay-disabled-bg)] text-[var(--overlay-disabled-text)]'\n : ''\n }`}\n style={{ height: '28px' }}\n required\n />\n </div>\n\n <div className=\"space-y-1\">\n <p className=\"text-[12px] leading-[18px] text-[var(--modal-text)]\">API Key</p>\n <PasswordField\n data-testid=\"models-create-model-api-key-input\"\n name=\"cc_model_api_key\"\n value={modelApiKeyInput}\n onChange={(event) => onModelApiKeyChange(event.target.value)}\n placeholder=\"请输入API Key\"\n autoComplete=\"new-password\"\n autoCorrect=\"off\"\n autoCapitalize=\"off\"\n spellCheck={false}\n className=\"ui-input w-full\"\n style={{ height: '28px' }}\n required\n toggleTestId=\"models-create-model-api-key-toggle\"\n />\n </div>\n\n <div className=\"space-y-1\">\n <p className=\"text-[12px] leading-[18px] text-[var(--modal-text)]\">请求头(可选)</p>\n <div className=\"space-y-2\">\n {headerRows.map((row, index) => {\n const rowErrors = headerRowErrors.get(row.id) || {};\n return (\n <div\n key={row.id}\n className=\"flex flex-col gap-1\"\n data-testid={`models-create-model-header-row-${index}`}\n data-error-row={rowErrors.keyError || rowErrors.valueError ? 'true' : 'false'}\n >\n <div className=\"flex items-center gap-[4px]\">\n <input\n type=\"text\"\n value={row.key}\n onChange={(event) => onHeaderRowChange(row.id, 'key', event.target.value)}\n placeholder=\"请求头的键名\"\n className={`ui-input h-[28px] flex-1 ${\n rowErrors.keyError ? 'border-[var(--state-error-text)] bg-[var(--state-error-surface)]' : ''\n }`}\n data-testid={`models-create-model-header-key-${index}`}\n />\n <input\n type=\"text\"\n value={row.value}\n onChange={(event) => onHeaderRowChange(row.id, 'value', event.target.value)}\n placeholder=\"请求头的值\"\n className={`ui-input h-[28px] flex-1 ${\n rowErrors.valueError ? 'border-[var(--state-error-text)] bg-[var(--state-error-surface)]' : ''\n }`}\n data-testid={`models-create-model-header-value-${index}`}\n />\n <button\n type=\"button\"\n onClick={() => onRemoveHeaderRow(row.id)}\n aria-label={`请求头 ${index + 1}`}\n className=\"inline-flex h-6 w-6 min-h-6 min-w-6 items-center justify-center rounded-[8px] p-0 text-[var(--icon-delete-color)] transition-colors hover:bg-[var(--modal-muted-surface-hover)]\"\n data-testid={`models-create-model-header-remove-${index}`}\n >\n <MaskIcon name=\"delete\" className=\"h-4 w-4\" />\n </button>\n </div>\n {(rowErrors.keyError || rowErrors.valueError) && (\n <div className=\"break-all px-1 text-xs text-[var(--state-error-text)]\">\n {rowErrors.keyError || rowErrors.valueError}\n </div>\n )}\n </div>\n );\n })}\n <button\n type=\"button\"\n onClick={onAddHeaderRow}\n className=\"group inline-flex items-center gap-[4px] leading-[18px] text-[12px] text-[var(--text-accent)]\"\n data-testid=\"models-create-model-header-add\"\n >\n <MaskIcon name=\"add\" className=\"h-4 w-4\" />\n <span className=\"inline-flex h-[18px] items-center border-b border-transparent transition-colors group-hover:border-current\">\n 添加\n </span>\n </button>\n </div>\n {createError && createError.includes('请求头键名重复') ? (\n <p className=\"mt-1 text-xs text-[var(--state-error-text)]\">{createError}</p>\n ) : null}\n </div>\n </div>\n\n <div className=\"flex items-center justify-end gap-2\">\n <Button variant=\"default\" onClick={onClose}>\n {CREATE_MODEL_CANCEL_LABEL}\n </Button>\n <Button variant=\"default\"\n disabled={!canConfirm || testingConnection || isIconUploading || editModelBusy}\n onClick={onTestConnection}\n data-testid=\"models-test-connection\"\n >\n {testingConnection ? '测试中...' : TEST_CONNECTION_LABEL}\n </Button>\n <Button\n disabled={!canConfirm || saveModelBusy || isIconUploading || editModelBusy}\n onClick={onCreate}\n data-testid=\"models-create-model-confirm\"\n >\n {saveModelBusy ? '保存中...' : SAVE_MODEL_LABEL}\n </Button>\n </div>\n </div>\n </div>\n );\n}","/*\n * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n */\n\nimport { AppModal } from '@/components/AppModal';\nimport { Button } from '@/components/shared/Button';\nimport { CREATE_MODEL_RISK_MESSAGE, CREATE_MODEL_RISK_TITLE } from '../utils';\n\nexport interface CreateModelRiskModalProps {\n show: boolean;\n onClose: () => void;\n onAgree: () => void;\n}\n\nexport function CreateModelRiskModal({ show, onClose, onAgree }: CreateModelRiskModalProps) {\n return (\n <AppModal\n open={show}\n onClose={onClose}\n title={CREATE_MODEL_RISK_TITLE}\n panelClassName=\"w-[550px]\"\n disableBackdropClose\n showCloseButton={true}\n backdropTestId=\"models-create-model-risk-modal\"\n panelTestId=\"models-create-model-risk-modal-panel\"\n >\n <div className=\"space-y-4 pt-[18px]\">\n <p className=\"text-[12px] leading-[18px] text-[var(--text-secondary)]\">{CREATE_MODEL_RISK_MESSAGE}</p>\n <div className=\"flex items-center justify-end gap-2\">\n <Button variant=\"default\"\n size=\"md\"\n data-testid=\"models-create-model-risk-cancel\"\n onClick={onClose}\n >\n 取消\n </Button>\n <Button variant=\"major\"\n size=\"md\"\n data-testid=\"models-create-model-risk-confirm\"\n onClick={onAgree}\n >\n 我已同意\n </Button>\n </div>\n </div>\n </AppModal>\n );\n}","/*\n * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n */\n\nimport { PasswordField } from '@/components/shared/PasswordField';\nimport { TagEditor } from '@/components/hub-tag-editor';\nimport { Textarea } from '@/components/shared/Textarea';\nimport { SAVE_MODEL_LABEL, ADD_MODEL } from '../utils';\nimport type { UseAddModelFormResult } from '../hooks/useAddModelForm';\n\nexport interface AddModelModalProps {\n show: boolean;\n onClose: () => void;\n form: UseAddModelFormResult;\n}\n\nexport function AddModelModal({ show, onClose, form }: AddModelModalProps) {\n if (!show) return null;\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-[var(--overlay-backdrop-strong)] p-4\"\n data-testid=\"models-add-model-modal\"\n >\n <div className=\"max-h-[90vh] w-full max-w-xl overflow-y-auto rounded-2xl border border-[var(--modal-border)] bg-[var(--modal-surface)] p-5 shadow-[var(--modal-shadow)]\">\n <div className=\"mb-4 flex items-center justify-between\">\n <h3 className=\"text-base font-semibold text-[var(--modal-title-text)]\">{ADD_MODEL}</h3>\n <button\n type=\"button\"\n onClick={() => {\n form.reset();\n onClose();\n }}\n className=\"rounded-lg border border-[var(--button-default-border)] bg-[var(--button-default-bg)] px-3 py-1.5 text-xs font-medium text-[var(--button-default-text)] transition-colors hover:border-[var(--button-default-border-hover)] hover:bg-[var(--button-default-bg-hover)] hover:text-[var(--button-default-text-hover)]\"\n >\n 关闭\n </button>\n </div>\n <div className=\"space-y-3\">\n {form.error ? <p className=\"ui-status-error rounded-lg px-3 py-2 text-sm\">{form.error}</p> : null}\n <select\n value=\"openai\"\n disabled\n aria-label=\"协议\"\n className=\"w-full rounded border border-[var(--overlay-disabled-border)] bg-[var(--overlay-disabled-bg)] px-3 py-2 text-sm text-[var(--overlay-disabled-text)]\"\n >\n <option value=\"openai\">OpenAI</option>\n </select>\n <input\n value={form.displayName}\n onChange={(event) => form.setDisplayName(event.target.value)}\n placeholder=\"显示名称,如 My OpenAI Proxy\"\n autoComplete=\"off\"\n className=\"ui-input w-full\"\n />\n <input\n value={form.baseUrl}\n onChange={(event) => form.setBaseUrl(event.target.value)}\n placeholder=\"Base URL,如 https://api.example.com/v1\"\n autoComplete=\"off\"\n className=\"ui-input w-full\"\n />\n <PasswordField\n autoComplete=\"off\"\n value={form.apiKey}\n onChange={(event) => form.setApiKey(event.target.value)}\n placeholder=\"API Key\"\n className=\"ui-input w-full rounded px-3 py-2 text-sm\"\n toggleTestId=\"models-create-source-api-key-toggle\"\n />\n <Textarea\n value={form.headersText}\n onChange={(event) => form.setHeadersText(event.target.value)}\n rows={4}\n placeholder={'可选请求头(JSON),如 {\"X-App-Id\":\"my-app\"}'}\n useDefaultContainerStyles={false}\n useDefaultTextareaStyles={false}\n className=\"ui-textarea w-full rounded px-3 py-2 text-sm\"\n />\n <div className=\"space-y-2\">\n <p className=\"text-xs font-semibold text-[var(--modal-text-muted)]\">可用模型 *</p>\n <TagEditor\n tags={form.models}\n tone=\"purple\"\n addLabel=\"+ 添加模型\"\n placeholder=\"输入模型名,如 gpt-4o-mini\"\n emptyLabel=\"(至少添加 1 个模型)\"\n onChange={form.setModels}\n minCount={0}\n />\n </div>\n {form.successMessage ? (\n <p className=\"ui-status-success rounded-lg px-3 py-2 text-sm\">{form.successMessage}</p>\n ) : null}\n <div className=\"flex items-center justify-end gap-2\">\n <button\n type=\"button\"\n disabled={form.saveBusy || !form.canCreate}\n onClick={() => void form.handleSave()}\n className=\"rounded bg-[var(--button-primary-bg)] px-3 py-1.5 text-xs font-medium text-[var(--button-primary-text)] transition-colors hover:bg-[var(--button-primary-bg-hover)] hover:text-[var(--button-primary-text-hover)] disabled:bg-[var(--button-disabled-bg)] disabled:text-[var(--button-disabled-text)] disabled:opacity-50\"\n >\n {form.saveBusy ? '保存中...' : SAVE_MODEL_LABEL}\n </button>\n </div>\n </div>\n </div>\n </div>\n );\n}","/*\n * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n */\n\nimport { Button } from '@/components/shared/Button';\nimport { MaskIcon } from '@/components/shared/MaskIcon';\nimport { HUAWEI_MAAS_SERVICE_CONFIGS } from '../utils';\nimport type { HuaweiMaasServiceType } from '../utils';\n\nexport interface HuaweiMaasAccessModalProps {\n show: boolean;\n activeServiceType: HuaweiMaasServiceType;\n apiKey: string;\n loading: boolean;\n saving: boolean;\n canConfirm: boolean;\n activeHasApiKey: boolean;\n updatingApiKey: boolean;\n apiKeyUrl: string;\n onServiceTypeChange: (value: HuaweiMaasServiceType) => void;\n onApiKeyChange: (value: string) => void;\n onUpdateApiKey: () => void;\n onClose: () => void;\n onConfirm: () => void;\n}\n\nexport function HuaweiMaasAccessModal({\n show,\n activeServiceType,\n apiKey,\n loading,\n saving,\n canConfirm,\n activeHasApiKey,\n updatingApiKey,\n apiKeyUrl,\n onServiceTypeChange,\n onApiKeyChange,\n onUpdateApiKey,\n onClose,\n onConfirm,\n}: HuaweiMaasAccessModalProps) {\n if (!show) return null;\n\n return (\n <div\n className=\"fixed inset-0 z-50 flex items-start justify-center bg-[var(--overlay-backdrop-strong)] px-4 pt-[96px]\"\n data-testid=\"models-huawei-maas-access-modal\"\n >\n <div className=\"relative w-full max-w-[640px] rounded-[8px] border border-[var(--modal-border)] bg-[var(--modal-surface)] p-6 shadow-[var(--modal-shadow)]\">\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"close\"\n className=\"absolute right-5 top-5 flex h-6 w-6 items-center justify-center rounded text-[var(--modal-close-icon)] transition-colors hover:bg-[var(--modal-close-hover-bg)] hover:text-[var(--modal-close-icon-hover)]\"\n >\n <MaskIcon name=\"close\" className=\"h-4 w-4\" />\n </button>\n\n <div className=\"pr-10\">\n <h3 className=\"text-[16px] font-bold text-[var(--modal-title-text)]\">接入MaaS模型</h3>\n </div>\n\n <div className=\"mt-5 space-y-4\">\n <div className=\"space-y-2\">\n <div className=\"text-[12px] leading-[18px] text-[var(--modal-text)]\">接入类型</div>\n <div className=\"flex flex-wrap gap-2\">\n {(['claw-plan', 'maas'] as const).map((serviceType) => {\n const active = activeServiceType === serviceType;\n return (\n <button\n key={serviceType}\n type=\"button\"\n onClick={() => onServiceTypeChange(serviceType)}\n className={[\n 'h-[28px] min-w-[156px] rounded-[6px] border px-4 text-[12px] transition-colors',\n active\n ? 'border-[#1677ff] bg-white text-[#1677ff]'\n : 'border-[var(--border-default)] bg-[var(--surface-panel)] text-[var(--text-primary)] hover:border-[#1677ff]',\n ].join(' ')}\n data-testid={`models-huawei-maas-service-${serviceType}`}\n >\n {HUAWEI_MAAS_SERVICE_CONFIGS[serviceType].label}\n </button>\n );\n })}\n </div>\n </div>\n\n <div className=\"space-y-2\">\n <div className=\"text-[12px] leading-[18px] text-[var(--modal-text)]\">API Key</div>\n <div className=\"flex items-center gap-2\">\n <input\n type=\"text\"\n data-testid=\"models-huawei-maas-api-key-input\"\n name=\"huawei_maas_api_key\"\n value={apiKey}\n onChange={(event) => onApiKeyChange(event.target.value)}\n placeholder=\"立即创建或粘贴已有的“西南-贵阳一”API Key\"\n autoComplete=\"off\"\n autoCorrect=\"off\"\n autoCapitalize=\"off\"\n spellCheck={false}\n disabled={(activeHasApiKey && !updatingApiKey) || loading || saving}\n className=\"ui-input h-[28px] min-w-0 flex-1 disabled:bg-[#f3f4f6] disabled:text-[var(--text-muted)]\"\n />\n {activeHasApiKey && !updatingApiKey ? (\n <button\n type=\"button\"\n onClick={onUpdateApiKey}\n className=\"shrink-0 text-[12px] text-[var(--text-accent)] hover:underline\"\n data-testid=\"models-huawei-maas-api-key-update\"\n >\n 更新\n </button>\n ) : (\n <a\n href={apiKeyUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"shrink-0 text-[12px] text-[var(--text-accent)] hover:underline\"\n >\n 创建API Key\n </a>\n )}\n </div>\n </div>\n </div>\n\n <div className=\"mt-5 flex items-center justify-end gap-2\">\n <Button variant=\"default\" onClick={onClose} disabled={saving}>\n 取消\n </Button>\n <Button\n disabled={!canConfirm}\n loading={saving}\n onClick={onConfirm}\n data-testid=\"models-huawei-maas-confirm\"\n >\n 确认\n </Button>\n </div>\n </div>\n </div>\n );\n}\n","/*\n * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n */\n\n'use client';\n\nimport { useCallback, useState } from 'react';\nimport { useEscapeKey } from '@/hooks/useEscapeKey';\nimport { useConfirm } from '@/components/useConfirm';\nimport { apiFetch } from '@/utils/api-client';\nimport { useChatStore } from '@/stores/chatStore';\nimport { CenteredLoadingState } from '@/components/shared/CenteredLoadingState';\nimport { EmptyDataState } from '@/components/shared/EmptyDataState';\nimport { NoSearchResultsState } from '@/components/shared/NoSearchResultsState';\nimport { hasCreateModelRiskAgreed, markCreateModelRiskAgreed, EMPTY_STATE_TITLE } from './utils';\nimport { useModelsPanelData } from './hooks/useModelsPanelData';\nimport { useCreateModelForm } from './hooks/useCreateModelForm';\nimport { useAddModelForm } from './hooks/useAddModelForm';\nimport { useHuaweiMaasAccessForm } from './hooks/useHuaweiMaasAccessForm';\nimport { ModelsToolbar } from './components/ModelsToolbar';\nimport { ModelGroupSection } from './components/ModelGroupSection';\nimport { CreateModelModal } from './components/CreateModelModal';\nimport { CreateModelRiskModal } from './components/CreateModelRiskModal';\nimport { AddModelModal } from './components/AddModelModal';\nimport { HuaweiMaasAccessModal } from './components/HuaweiMaasAccessModal';\nimport type { ModelCardData } from './types/models-panel';\n\nfunction parseModelConfigCardId(cardId: string): { sourceId: string; modelName: string } | null {\n const prefix = 'model_config:';\n if (!cardId.startsWith(prefix)) return null;\n const rest = cardId.slice(prefix.length);\n const separatorIndex = rest.indexOf(':');\n if (separatorIndex <= 0) return null;\n const sourceId = rest.slice(0, separatorIndex).trim();\n const modelName = rest.slice(separatorIndex + 1).trim();\n return sourceId && modelName ? { sourceId, modelName } : null;\n}\n\nexport function ModelsPanel() {\n const confirm = useConfirm();\n const currentProjectPath = useChatStore((s) => s.currentProjectPath);\n const [deletingModelId, setDeletingModelId] = useState<string | null>(null);\n const [showAddModelModal, setShowAddModelModal] = useState(false);\n const [showHuaweiMaasAccessModal, setShowHuaweiMaasAccessModal] = useState(false);\n\n const modelsData = useModelsPanelData();\n const fetchModels = modelsData.fetchModels;\n const createForm = useCreateModelForm(modelsData.resolvedProjectPath, fetchModels);\n const closeHuaweiMaasAccessModal = useCallback(() => {\n setShowHuaweiMaasAccessModal(false);\n }, []);\n const huaweiMaasAccessForm = useHuaweiMaasAccessForm(\n showHuaweiMaasAccessModal,\n closeHuaweiMaasAccessModal,\n fetchModels,\n );\n\n const addModelForm = useAddModelForm(\n currentProjectPath && currentProjectPath !== 'default' ? currentProjectPath : null,\n async () => {\n await fetchModels();\n setShowAddModelModal(false);\n },\n () => {}, // error handled internally by form\n );\n\n const handleDeleteModel = useCallback(\n async (cardId: string, cardName: string) => {\n if (deletingModelId) return;\n const ok = await confirm({\n title: '删除模型',\n message: `确认删除模型\"${cardName || cardId}\"?此操作不可恢复。`,\n confirmLabel: '删除',\n cancelLabel: '取消',\n variant: 'default',\n });\n if (!ok) return;\n setDeletingModelId(cardId);\n try {\n let sourceId = cardId;\n const modelConfigCard = parseModelConfigCardId(cardId);\n if (modelConfigCard) sourceId = modelConfigCard.sourceId;\n const query = new URLSearchParams();\n if (currentProjectPath && currentProjectPath !== 'default') {\n query.set('projectPath', currentProjectPath);\n }\n const queryText = query.toString();\n let res: Response;\n if (modelConfigCard) {\n const profilesUrl = `/api/model-config-profiles${queryText ? `?${queryText}` : ''}`;\n const profilesRes = await apiFetch(profilesUrl);\n if (!profilesRes.ok) {\n const body = (await profilesRes.json().catch(() => ({}))) as { error?: string };\n throw new Error(body.error ?? `读取模型配置失败 (${profilesRes.status})`);\n }\n const profilesBody = (await profilesRes.json().catch(() => ({}))) as {\n providers?: Array<{ id: string; models?: string[] }>;\n };\n const sourceProfile = profilesBody.providers?.find((profile) => profile.id === sourceId);\n if (!sourceProfile) {\n throw new Error(`模型源 \"${sourceId}\" 不存在`);\n }\n const sourceModels = sourceProfile.models?.map((model) => model.trim()).filter(Boolean) ?? [];\n if (!sourceModels.includes(modelConfigCard.modelName)) {\n throw new Error(`模型 \"${modelConfigCard.modelName}\" 不存在`);\n }\n const remainingModels = sourceModels.filter((model) => model !== modelConfigCard.modelName);\n if (sourceModels.length > 1 && remainingModels.length > 0) {\n res = await apiFetch(`/api/model-config-profiles/${encodeURIComponent(sourceId)}`, {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n ...(currentProjectPath && currentProjectPath !== 'default' ? { projectPath: currentProjectPath } : {}),\n models: remainingModels,\n }),\n });\n } else {\n const url = `/api/model-config-profiles/${encodeURIComponent(sourceId)}${queryText ? `?${queryText}` : ''}`;\n res = await apiFetch(url, { method: 'DELETE' });\n }\n } else {\n const url = `/api/model-config-profiles/${encodeURIComponent(sourceId)}${queryText ? `?${queryText}` : ''}`;\n res = await apiFetch(url, { method: 'DELETE' });\n }\n if (!res.ok) {\n const body = (await res.json().catch(() => ({}))) as { error?: string };\n throw new Error(body.error ?? `删除失败 (${res.status})`);\n }\n await fetchModels();\n } catch (error) {\n console.error('Delete model failed:', error);\n } finally {\n setDeletingModelId(null);\n }\n },\n [confirm, deletingModelId, currentProjectPath, fetchModels],\n );\n\n const handleOpenCreateModelRiskGuard = useCallback(() => {\n if (hasCreateModelRiskAgreed()) {\n createForm.openModal('default');\n return;\n }\n createForm.openRiskModal();\n }, [createForm]);\n\n useEscapeKey({\n enabled: createForm.showModal || createForm.showRiskModal || showHuaweiMaasAccessModal,\n onEscape: () => {\n if (showHuaweiMaasAccessModal) {\n closeHuaweiMaasAccessModal();\n return;\n }\n if (createForm.showRiskModal) {\n createForm.closeRiskModal();\n return;\n }\n createForm.closeModal();\n },\n });\n\n return (\n <div className=\"ui-page-shell overflow-hidden\">\n <ModelsToolbar\n loading={modelsData.loading}\n isSkipAuth={modelsData.isSkipAuth}\n canCreateModel={modelsData.canCreateModel}\n searchQuery={modelsData.searchQuery}\n onSearchChange={modelsData.setSearchQuery}\n onRefresh={() => void modelsData.fetchModels()}\n onOpenCreateModel={handleOpenCreateModelRiskGuard}\n onOpenHuaweiMaasAccess={() => setShowHuaweiMaasAccessModal(true)}\n />\n\n <div className=\"flex-1 min-h-0 overflow-y-auto pb-2\" data-testid=\"models-scroll-region\">\n <div className=\"flex flex-col gap-4 h-full\">\n {modelsData.loading && (\n <div className=\"flex flex-1 min-h-0 items-center justify-center py-10\" data-testid=\"models-loading-state\">\n <CenteredLoadingState />\n </div>\n )}\n\n {modelsData.showEmptyData && (\n <div className=\"flex flex-1 min-h-0 items-center justify-center py-10\" data-testid=\"models-empty-state\">\n <EmptyDataState title={EMPTY_STATE_TITLE} />\n </div>\n )}\n\n {modelsData.showNoResults && (\n <div className=\"flex flex-1 min-h-0 items-center justify-center py-10\" data-testid=\"models-no-results-state\">\n <NoSearchResultsState onClear={() => modelsData.setSearchQuery('')} />\n </div>\n )}\n\n {modelsData.showGroups &&\n modelsData.groupedCards.map((group) => (\n <ModelGroupSection\n key={group.key}\n group={group}\n deletingModelId={deletingModelId}\n editModelBusy={createForm.editModelBusy}\n onEdit={(card: ModelCardData) => void createForm.handleOpenEditModelModal(card)}\n onDelete={handleDeleteModel}\n />\n ))}\n </div>\n </div>\n\n <CreateModelRiskModal\n show={createForm.showRiskModal}\n onClose={createForm.closeRiskModal}\n onAgree={() => {\n markCreateModelRiskAgreed();\n createForm.handleAgreeRisk();\n }}\n />\n\n <CreateModelModal\n show={createForm.showModal}\n onClose={createForm.closeModal}\n modalMode={createForm.modalMode}\n isEditMode={createForm.isEditMode}\n modelNameInput={createForm.modelNameInput}\n onModelNameChange={createForm.setModelNameInput}\n modelDescriptionInput={createForm.modelDescriptionInput}\n onModelDescriptionChange={createForm.setModelDescriptionInput}\n modelIconInput={createForm.modelIconInput}\n onModelIconChange={createForm.setModelIconInput}\n modelDisplayNameInput={createForm.modelDisplayNameInput}\n onModelDisplayNameChange={createForm.setModelDisplayNameInput}\n modelUrlInput={createForm.modelUrlInput}\n onModelUrlChange={createForm.setModelUrlInput}\n modelApiKeyInput={createForm.modelApiKeyInput}\n onModelApiKeyChange={createForm.setModelApiKeyInput}\n headerRows={createForm.headerRows}\n headerRowErrors={createForm.headerRowErrors}\n headerErrorRowIndex={createForm.headerErrorRowIndex}\n onAddHeaderRow={createForm.handleAddHeaderRow}\n onHeaderRowChange={createForm.handleHeaderRowChange}\n onRemoveHeaderRow={createForm.handleRemoveHeaderRow}\n isModelNameValid={createForm.isModelNameValid}\n showModelNameValidationError={createForm.showModelNameValidationError}\n canConfirm={createForm.canConfirm}\n createError={createForm.createError}\n saveModelBusy={createForm.saveModelBusy}\n testingConnection={createForm.saveModelBusy}\n editModelBusy={createForm.editModelBusy}\n onCreate={() => void createForm.handleCreateModel()}\n onTestConnection={() => void createForm.handleTestConnection()}\n />\n\n <AddModelModal\n show={showAddModelModal}\n onClose={() => {\n addModelForm.reset();\n setShowAddModelModal(false);\n }}\n form={addModelForm}\n />\n\n <HuaweiMaasAccessModal\n show={showHuaweiMaasAccessModal}\n activeServiceType={huaweiMaasAccessForm.activeServiceType}\n apiKey={huaweiMaasAccessForm.apiKey}\n loading={huaweiMaasAccessForm.loading}\n saving={huaweiMaasAccessForm.saving}\n canConfirm={huaweiMaasAccessForm.canConfirm}\n activeHasApiKey={huaweiMaasAccessForm.activeHasApiKey}\n updatingApiKey={huaweiMaasAccessForm.updatingApiKey}\n apiKeyUrl={huaweiMaasAccessForm.apiKeyUrl}\n onServiceTypeChange={huaweiMaasAccessForm.setActiveServiceType}\n onApiKeyChange={huaweiMaasAccessForm.setApiKey}\n onUpdateApiKey={huaweiMaasAccessForm.startApiKeyUpdate}\n onClose={closeHuaweiMaasAccessModal}\n onConfirm={() => void huaweiMaasAccessForm.handleConfirm()}\n />\n </div>\n );\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\nimport { ModelsPanel } from '@/components/models-panel/ModelsPanel';\n\nexport default function ModelsPage() {\n return (\n <div className=\"h-full overflow-hidden ui-shell-surface px-8 py-8\">\n <ModelsPanel />\n </div>\n );\n}\n"],"names":["useModelsPanelData","loading","setLoading","useState","isSkipAuth","setIsSkipAuth","canCreateModel","setCanCreateModel","searchQuery","setSearchQuery","cards","setCards","resolvedProjectPath","setResolvedProjectPath","currentProjectPath","useChatStore","s","buildModelsUrl","useCallback","query","queryText","buildModelConfigProfilesUrl","fetchModels","modelsRes","providersRes","apiFetch","json","providersJson","providerUpdatedAtById","provider","normalizeUpdatedAt","source","normalizeModel","card","sourceId","resolveModelConfigSourceId","updatedAt","useEffect","getIsSkipAuth","getCanCreateModel","isEnvFlagEnabled","readBuildEnv","normalizedQuery","useMemo","filteredCards","buildModelSearchText","groupedCards","groupCards","hasSearchQuery","showEmptyData","showNoResults","showGroups","useHeaderRowsEditor","rows","setRows","rowErrors","setRowErrors","errorRowIndex","setErrorRowIndex","validateRows","targetRows","newErrors","keyCountMap","row","index","key","value","existing","indices","rowId","handleAddRow","errors","err","nextRow","createEmptyHeaderRow","prev","handleRowChange","field","updatedRows","handleRemoveRow","resetRows","clearErrors","setRowsFromHeaders","headers","headersObjectToRows","useCreateModelForm","showModal","setShowModal","modalMode","setModalMode","createError","setCreateError","createModelSuccess","setCreateModelSuccess","saveModelBusy","setSaveModelBusy","modelNameInput","setModelNameInput","modelDescriptionInput","setModelDescriptionInput","modelIconInput","setModelIconInput","modelDisplayNameInput","setModelDisplayNameInput","modelUrlInput","setModelUrlInput","modelApiKeyInput","setModelApiKeyInput","editingSourceId","setEditingSourceId","editingOriginalModelName","setEditingOriginalModelName","editingSourceModels","setEditingSourceModels","editingModelBaseUrls","setEditingModelBaseUrls","editingModelDescriptions","setEditingModelDescriptions","editingModelIcons","setEditingModelIcons","editModelBusy","setEditModelBusy","showRiskModal","setShowRiskModal","headerEditor","isEditMode","isHuaweiMaasAccessMode","HUAWEI_MAAS_ACCESS_MODAL_MODE","resolveProjectPathForPayload","trimmedModelName","isModelNameValid","isValidModelName","showModelNameValidationError","canConfirm","resetForm","mode","DEFAULT_MODEL_ICON_SRC","HUAWEI_MAAS_ACCESS_URL","closeModal","openModal","openRiskModal","closeRiskModal","handleAgreeRisk","resolveDraftModelNames","nextModel","previousModel","replacedModels","name","handleCreateModel","buildResult","buildHeadersObject","description","displayName","icon","projectPath","method","url","payload","mergedModels","nextModelBaseUrls","model","baseUrl","entry","nextModelDescriptions","nextModelIcons","generateModelConfigSourceId","HUAWEI_MAAS_ACCESS_MODE","res","body","error","handleTestConnection","apiKey","modelName","showToast","useToastStore","handleOpenEditModelModal","_a","apiUrl","item","_b","_d","_c","_e","_f","_g","cardId","parts","useAddModelForm","onCreated","onError","setSourceId","setDisplayName","setBaseUrl","setApiKey","headersText","setHeadersText","models","setModels","saveBusy","setSaveBusy","setError","successMessage","setSuccessMessage","canCreate","reset","handleSave","parseHeadersJson","saveError","errorMessage","useHuaweiMaasAccessForm","open","onClose","onSaved","activeServiceType","setActiveServiceType","providersByService","setProvidersByService","saving","setSaving","updatingApiKey","setUpdatingApiKey","existingApiKey","activeHasApiKey","apiKeyUrl","readPublicEnv","DEFAULT_MAAS_API_KEY_URL","profilesUrl","loadProfiles","nextProviders","serviceType","resolveHuaweiMaasServiceType","sharedApiKey","startApiKeyUpdate","handleConfirm","trimmedApiKey","config","HUAWEI_MAAS_SERVICE_CONFIGS","modelBaseUrls","id","baseUrlEntries","resolveHuaweiMaasAccessModelIds","basePayload","isUpdate","ModelsToolbar","onSearchChange","onRefresh","onOpenCreateModel","onOpenHuaweiMaasAccess","openHub","jsxs","Fragment","jsx","MODEL_TITLE","Button","HUAWEI_MAAS_ACCESS_LABEL","CREATE_MODEL_LABEL","SearchInput","SEARCH_PLACEHOLDER","MaskIcon","ClockIcon","ModelCard","groupKey","deletingModelId","onEdit","onDelete","cardIconSrc","resolveUploadedIconUrl","customModelUpdatedAt","HUAWEI_MAAS_PROTOCOL","formatCustomModelUpdatedAt","HUAWEI_MAAS_GROUP_KEY","NameInitialIcon","OverflowTooltip","label","VENDOR_ICON","ModelGroupSection","group","CloseIcon","CreateModelModal","show","onModelNameChange","onModelDescriptionChange","onModelIconChange","onModelDisplayNameChange","onModelUrlChange","onModelApiKeyChange","headerRows","headerRowErrors","headerErrorRowIndex","onAddHeaderRow","onHeaderRowChange","onRemoveHeaderRow","testingConnection","onCreate","onTestConnection","modelIconFileInputRef","useRef","isIconUploading","setIsIconUploading","modelIconPreviewSrc","errorRow","handleModelIconUpload","event","file","MODEL_ICON_MAX_BYTES","uploaded","uploadAvatarAsset","MODEL_NAME_VALIDATION_MESSAGE","Textarea","current","max","nextVariant","buildNameInitialIconDataUrl","PasswordField","CREATE_MODEL_CANCEL_LABEL","TEST_CONNECTION_LABEL","SAVE_MODEL_LABEL","CreateModelRiskModal","onAgree","AppModal","CREATE_MODEL_RISK_TITLE","CREATE_MODEL_RISK_MESSAGE","AddModelModal","form","ADD_MODEL","TagEditor","HuaweiMaasAccessModal","onServiceTypeChange","onApiKeyChange","onUpdateApiKey","onConfirm","active","parseModelConfigCardId","prefix","rest","separatorIndex","ModelsPanel","confirm","useConfirm","setDeletingModelId","showAddModelModal","setShowAddModelModal","showHuaweiMaasAccessModal","setShowHuaweiMaasAccessModal","modelsData","createForm","closeHuaweiMaasAccessModal","huaweiMaasAccessForm","addModelForm","handleDeleteModel","cardName","modelConfigCard","profilesRes","sourceProfile","profile","sourceModels","remainingModels","handleOpenCreateModelRiskGuard","hasCreateModelRiskAgreed","useEscapeKey","CenteredLoadingState","EmptyDataState","EMPTY_STATE_TITLE","NoSearchResultsState","markCreateModelRiskAgreed","ModelsPage"],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import{j as s}from"./index-Cb4fQgom.js";const i="#";function a(o){let t=0;for(const e of o)t=t*31+e.charCodeAt(0)>>>0;return t}function c(o){const t=o.trim();if(!t)return i;const[e]=Array.from(t);return/[a-z]/i.test(e)?e.toUpperCase():e}function m(o){const t=o.trim().toLowerCase()||"empty",r=`hsl(${a(t)%360} 66% 52%)`;return{background:`linear-gradient(145deg, color-mix(in srgb, var(--surface-card) 86%, ${r}) 0%, color-mix(in srgb, var(--accent-soft) 70%, ${r}) 100%)`,borderColor:`color-mix(in srgb, var(--border-soft) 60%, ${r})`,textColor:`color-mix(in srgb, var(--text-primary) 70%, ${r})`}}function x(o,t=0){const e=o.trim()||i,r=`${e.toLowerCase()}#${t}`,n=a(r)%360,l=c(e),d=`
|
|
2
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 96 96">
|
|
3
|
+
<rect width="96" height="96" rx="10" fill="${`hsl(${n} 52% 78%)`}" />
|
|
4
|
+
<text x="50%" y="55%" text-anchor="middle" dominant-baseline="middle" font-family="ui-sans-serif, system-ui, -apple-system, Segoe UI, sans-serif" font-size="38" font-weight="700" fill="#1F2937">${l}</text>
|
|
5
|
+
</svg>
|
|
6
|
+
`.trim();return`data:image/svg+xml;charset=UTF-8,${encodeURIComponent(d)}`}function f({name:o,className:t="",dataTestId:e}){const r=c(o),n=m(o);return s.jsx("div",{"aria-hidden":"true","data-testid":e,className:`inline-flex h-12 w-12 shrink-0 items-center justify-center rounded-[10px] border shadow-sm ${t}`.trim(),style:{background:n.background,borderColor:n.borderColor},children:s.jsx("span",{className:"select-none text-xl font-bold leading-none tracking-[0.02em]",style:{color:n.textColor},children:r})})}export{f as N,x as b};
|
|
7
|
+
//# sourceMappingURL=NameInitialIcon-DP-6_HQY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NameInitialIcon-DP-6_HQY.js","sources":["../../src/lib/name-initial-icon.ts","../../src/components/NameInitialIcon.tsx"],"sourcesContent":["/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\nexport interface NameInitialIconTheme {\n background: string;\n borderColor: string;\n textColor: string;\n}\nconst EMPTY_INITIAL_FALLBACK = '#';\n\nfunction stableHash(input: string): number {\n let hash = 0;\n for (const ch of input) {\n hash = (hash * 31 + ch.charCodeAt(0)) >>> 0;\n }\n return hash;\n}\n\nexport function getNameInitial(name: string): string {\n const trimmed = name.trim();\n if (!trimmed) return EMPTY_INITIAL_FALLBACK;\n const [initial] = Array.from(trimmed);\n return /[a-z]/i.test(initial) ? initial.toUpperCase() : initial;\n}\n\nexport function getNameInitialIconTheme(name: string): NameInitialIconTheme {\n const seed = name.trim().toLowerCase() || 'empty';\n const hue = stableHash(seed) % 360;\n const accent = `hsl(${hue} 66% 52%)`;\n\n return {\n background: `linear-gradient(145deg, color-mix(in srgb, var(--surface-card) 86%, ${accent}) 0%, color-mix(in srgb, var(--accent-soft) 70%, ${accent}) 100%)`,\n borderColor: `color-mix(in srgb, var(--border-soft) 60%, ${accent})`,\n textColor: `color-mix(in srgb, var(--text-primary) 70%, ${accent})`,\n };\n}\n\nexport function buildNameInitialIconDataUrl(name: string, variant = 0): string {\n const normalizedName = name.trim() || EMPTY_INITIAL_FALLBACK;\n const seed = `${normalizedName.toLowerCase()}#${variant}`;\n const baseHue = stableHash(seed) % 360;\n const label = getNameInitial(normalizedName);\n const background = `hsl(${baseHue} 52% 78%)`;\n const textColor = '#1F2937';\n\n const svg = `\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"96\" height=\"96\" viewBox=\"0 0 96 96\">\n <rect width=\"96\" height=\"96\" rx=\"10\" fill=\"${background}\" />\n <text x=\"50%\" y=\"55%\" text-anchor=\"middle\" dominant-baseline=\"middle\" font-family=\"ui-sans-serif, system-ui, -apple-system, Segoe UI, sans-serif\" font-size=\"38\" font-weight=\"700\" fill=\"${textColor}\">${label}</text>\n </svg>\n `.trim();\n\n return `data:image/svg+xml;charset=UTF-8,${encodeURIComponent(svg)}`;\n}\n","/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\nimport { getNameInitial, getNameInitialIconTheme } from '@/lib/name-initial-icon';\n\nexport function NameInitialIcon({\n name,\n className = '',\n dataTestId,\n}: {\n name: string;\n className?: string;\n dataTestId?: string;\n}) {\n const initial = getNameInitial(name);\n const theme = getNameInitialIconTheme(name);\n\n return (\n <div\n aria-hidden=\"true\"\n data-testid={dataTestId}\n className={`inline-flex h-12 w-12 shrink-0 items-center justify-center rounded-[10px] border shadow-sm ${className}`.trim()}\n style={{ background: theme.background, borderColor: theme.borderColor }}\n >\n <span className=\"select-none text-xl font-bold leading-none tracking-[0.02em]\" style={{ color: theme.textColor }}>\n {initial}\n </span>\n </div>\n );\n}\n"],"names":["EMPTY_INITIAL_FALLBACK","stableHash","input","hash","ch","getNameInitial","name","trimmed","initial","getNameInitialIconTheme","seed","accent","buildNameInitialIconDataUrl","variant","normalizedName","baseHue","label","svg","NameInitialIcon","className","dataTestId","theme","jsx"],"mappings":"wCAWA,MAAMA,EAAyB,IAE/B,SAASC,EAAWC,EAAuB,CACzC,IAAIC,EAAO,EACX,UAAWC,KAAMF,EACfC,EAAQA,EAAO,GAAKC,EAAG,WAAW,CAAC,IAAO,EAE5C,OAAOD,CACT,CAEO,SAASE,EAAeC,EAAsB,CACnD,MAAMC,EAAUD,EAAK,KAAA,EACrB,GAAI,CAACC,EAAS,OAAOP,EACrB,KAAM,CAACQ,CAAO,EAAI,MAAM,KAAKD,CAAO,EACpC,MAAO,SAAS,KAAKC,CAAO,EAAIA,EAAQ,cAAgBA,CAC1D,CAEO,SAASC,EAAwBH,EAAoC,CAC1E,MAAMI,EAAOJ,EAAK,KAAA,EAAO,eAAiB,QAEpCK,EAAS,OADHV,EAAWS,CAAI,EAAI,GACN,YAEzB,MAAO,CACL,WAAY,uEAAuEC,CAAM,oDAAoDA,CAAM,UACnJ,YAAa,8CAA8CA,CAAM,IACjE,UAAW,+CAA+CA,CAAM,GAAA,CAEpE,CAEO,SAASC,EAA4BN,EAAcO,EAAU,EAAW,CAC7E,MAAMC,EAAiBR,EAAK,KAAA,GAAUN,EAChCU,EAAO,GAAGI,EAAe,YAAA,CAAa,IAAID,CAAO,GACjDE,EAAUd,EAAWS,CAAI,EAAI,IAC7BM,EAAQX,EAAeS,CAAc,EAIrCG,EAAM;AAAA;AAAA,mDAHO,OAAOF,CAAO,WAK0B;AAAA,0MACkJC,CAAK;AAAA;AAAA,IAEhN,KAAA,EAEF,MAAO,oCAAoC,mBAAmBC,CAAG,CAAC,EACpE,CChDO,SAASC,EAAgB,CAC9B,KAAAZ,EACA,UAAAa,EAAY,GACZ,WAAAC,CACF,EAIG,CACD,MAAMZ,EAAUH,EAAeC,CAAI,EAC7Be,EAAQZ,EAAwBH,CAAI,EAE1C,OACEgB,EAAAA,IAAC,MAAA,CACC,cAAY,OACZ,cAAaF,EACb,UAAW,8FAA8FD,CAAS,GAAG,KAAA,EACrH,MAAO,CAAE,WAAYE,EAAM,WAAY,YAAaA,EAAM,WAAA,EAE1D,SAAAC,EAAAA,IAAC,OAAA,CAAK,UAAU,+DAA+D,MAAO,CAAE,MAAOD,EAAM,WAClG,SAAAb,CAAA,CACH,CAAA,CAAA,CAGN"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{j as e,B as i}from"./index-Cb4fQgom.js";function x({onClear:t,className:s="",title:a="暂未匹配到数据",description:r="没有匹配到符合条件的数据",clearLabel:c="清空筛选器"}){return e.jsxs("div",{className:`flex flex-col items-center text-center ${s}`.trim(),"data-testid":"no-search-results-state",children:[e.jsx("img",{src:"/images/no-search-results.svg",alt:"","aria-hidden":"true","data-testid":"no-search-results-image",className:"mb-[18px] h-[60px] w-[60px] shrink-0"}),e.jsxs("div",{className:"flex flex-col items-center gap-1","data-testid":"no-search-results-copy",children:[e.jsx("p",{className:"text-sm font-medium text-[var(--text-primary)]",children:a}),e.jsx("p",{className:"text-xs text-[var(--text-muted)]",children:r})]}),e.jsx(i,{variant:"default",onClick:t,className:"mt-4 h-8 px-4 text-xs","data-testid":"no-search-results-clear",children:c})]})}export{x as N};
|
|
2
|
+
//# sourceMappingURL=NoSearchResultsState-BiiYdZ_Z.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NoSearchResultsState-BiiYdZ_Z.js","sources":["../../src/components/shared/NoSearchResultsState.tsx"],"sourcesContent":["/*\n * *\n * * Copyright (C) Huawei Technologies Co., Ltd. 2026. All rights reserved.\n *\n */\n\n'use client';\n\nimport { Button } from './Button';\n\ntype NoSearchResultsStateProps = {\n onClear?: () => void;\n className?: string;\n title?: string;\n description?: string;\n clearLabel?: string;\n};\n\nexport function NoSearchResultsState({\n onClear,\n className = '',\n title = '暂未匹配到数据',\n description = '没有匹配到符合条件的数据',\n clearLabel = '清空筛选器',\n}: NoSearchResultsStateProps) {\n return (\n <div\n className={`flex flex-col items-center text-center ${className}`.trim()}\n data-testid=\"no-search-results-state\"\n >\n <img\n src=\"/images/no-search-results.svg\"\n alt=\"\"\n aria-hidden=\"true\"\n data-testid=\"no-search-results-image\"\n className=\"mb-[18px] h-[60px] w-[60px] shrink-0\"\n />\n <div className=\"flex flex-col items-center gap-1\" data-testid=\"no-search-results-copy\">\n <p className=\"text-sm font-medium text-[var(--text-primary)]\">{title}</p>\n <p className=\"text-xs text-[var(--text-muted)]\">{description}</p>\n </div>\n <Button variant=\"default\"\n onClick={onClear}\n className=\"mt-4 h-8 px-4 text-xs\"\n data-testid=\"no-search-results-clear\"\n >\n {clearLabel}\n </Button>\n </div>\n );\n}\n"],"names":["NoSearchResultsState","onClear","className","title","description","clearLabel","jsxs","jsx","Button"],"mappings":"+CAkBO,SAASA,EAAqB,CACnC,QAAAC,EACA,UAAAC,EAAY,GACZ,MAAAC,EAAQ,UACR,YAAAC,EAAc,eACd,WAAAC,EAAa,OACf,EAA8B,CAC5B,OACEC,EAAAA,KAAC,MAAA,CACC,UAAW,0CAA0CJ,CAAS,GAAG,KAAA,EACjE,cAAY,0BAEZ,SAAA,CAAAK,EAAAA,IAAC,MAAA,CACC,IAAI,gCACJ,IAAI,GACJ,cAAY,OACZ,cAAY,0BACZ,UAAU,sCAAA,CAAA,EAEZD,EAAAA,KAAC,MAAA,CAAI,UAAU,mCAAmC,cAAY,yBAC5D,SAAA,CAAAC,EAAAA,IAAC,IAAA,CAAE,UAAU,iDAAkD,SAAAJ,EAAM,EACrEI,EAAAA,IAAC,IAAA,CAAE,UAAU,mCAAoC,SAAAH,CAAA,CAAY,CAAA,EAC/D,EACAG,EAAAA,IAACC,EAAA,CAAO,QAAQ,UACd,QAASP,EACT,UAAU,wBACV,cAAY,0BAEX,SAAAI,CAAA,CAAA,CACH,CAAA,CAAA,CAGN"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{r,j as f,a as nt}from"./index-Cb4fQgom.js";const rt={API_CLOWDER_HOST:"",BASE_URL:"/",CAN_CREATE_MODEL:"0",DEFAULT_API_CLIENT_URL:"http://127.0.0.1:3004",DEV:!1,MODE:"production",NEXT_PUBLIC_API_URL:"http://localhost:3004",NEXT_PUBLIC_BRAND_NAME:"OfficeClaw",NEXT_PUBLIC_SURVEY_CONTACT_ID:"web_home",NEXT_PUBLIC_SURVEY_ID:"agentarts_satisfaction",NEXT_PUBLIC_SURVEY_SERVICE_ID:"officeclaw",PROD:!0,SSR:!1};var F={};function Q(){try{return rt??{}}catch{return{}}}function $(t){if(typeof process<"u"&&F.VITEST){const e=F[t];if(e!==void 0)return e}return Q()[t]}function tt(t){if(typeof process<"u"&&F.VITEST){const o=F[t];if(o!==void 0)return o}const e=Q();return t==="API_CLOWDER_HOST"?e.API_CLOWDER_HOST??"":t==="DEFAULT_API_CLIENT_URL"?e.DEFAULT_API_CLIENT_URL??"http://127.0.0.1:3004":e.CAN_CREATE_MODEL??"0"}const N="office-claw-userId",M="cat-cafe-userId",K="office-claw-isskip",z="cat-cafe-isskip",st="can-create-model",B="office-claw-userName",j="cat-cafe-userName",G="default-user";function V(t,e){return typeof window>"u"?null:window.localStorage.getItem(t)??window.localStorage.getItem(e)}function Y(t,e,o){if(!(typeof window>"u")){window.localStorage.setItem(t,o);try{window.localStorage.removeItem(e)}catch{}}}function q(t,e){if(!(typeof window>"u"))try{window.localStorage.removeItem(t),window.localStorage.removeItem(e)}catch{}}function et(){if(typeof window>"u")return G;const e=new URL(window.location.href).searchParams.get("userId");if(e)return Y(N,M,e),e;const o=V(N,M);return o!==null&&o!==""?(window.localStorage.getItem(N)===null&&window.localStorage.getItem(M)!==null&&Y(N,M,o),o):G}function Et(){if(typeof window>"u")return"";const t=V(B,j);if(t)return window.localStorage.getItem(B)===null&&window.localStorage.getItem(j)!==null&&Y(B,j,t),t;const e=V(N,M)??"",o=e.split(":");return o.length>1?o[1]||o[0]:e}function gt(){const t=et(),e=t.indexOf(":");return e>0?t.slice(0,e):""}function Tt(){q(N,M),q(B,j)}function xt(){if(typeof window>"u")return!1;const t=V(K,z);return t===null?!1:(window.localStorage.getItem(K)===null&&window.localStorage.getItem(z)!==null&&Y(K,z,t),t==="1"||t==="true")}function It(){if(typeof window>"u")return!1;const t=localStorage.getItem(st);return t==="1"||t==="true"}const at=3600*1e3;function ot(){return typeof globalThis!="object"||globalThis===null?null:globalThis.location??null}function it(t){return t==="localhost"||t==="127.0.0.1"}const Z=$("NEXT_PUBLIC_PROD_API_URL")??"",lt=$("NEXT_PUBLIC_PROD_FRONTEND_HOST")??"",ct=tt("API_CLOWDER_HOST"),ut=tt("DEFAULT_API_CLIENT_URL");function dt(){const t=ot();if((t==null?void 0:t.hostname)===lt)return ct;if(it(t==null?void 0:t.hostname)){const d=(Number((t==null?void 0:t.port)??"")||3003)+1,i=(t==null?void 0:t.protocol)??"http:",m=(t==null?void 0:t.hostname)??"127.0.0.1";return`${i}//${m}:${d}`}const e=$("NEXT_PUBLIC_API_URL")||$("VITE_API_URL");if(e)return e.replace(/\/+$/,"");if(typeof window>"u")return ut;const g=(Number((t==null?void 0:t.port)??"")||3001)+1,u=(t==null?void 0:t.protocol)??"http:",l=(t==null?void 0:t.hostname)??"localhost";return`${u}//${l}:${g}`}const k=dt();function ft(t){if(t)return t;const e=ot();if(!e)return k.includes(Z)?"include":"same-origin";try{return new URL(k,e.href).origin===e.origin?"same-origin":"include"}catch{return k.includes(Z)?"include":"same-origin"}}async function Lt(t,e){const o=new Headers(e==null?void 0:e.headers);o.set("X-Office-Claw-User",et()),o.has("X-Trace-Id")||o.set("X-Trace-Id",crypto.randomUUID());const g=(e==null?void 0:e.timeoutMs)??at,u=new AbortController,l=setTimeout(()=>u.abort(),g),n=e==null?void 0:e.signal,d=()=>u.abort();n&&(n.aborted?u.abort():n.addEventListener("abort",d,{once:!0}));try{return await fetch(`${k}${t}`,{...e,headers:o,signal:u.signal,credentials:ft(e==null?void 0:e.credentials)})}finally{clearTimeout(l),n==null||n.removeEventListener("abort",d)}}const a=12,pt=10,H=6,h=328;function J(t,e,o){return Math.min(Math.max(t,e),o)}function ht(t,e,o){const g=r.useRef(null),u=r.useRef(null),l=r.useId(),[n,d]=r.useState(!1),[i,m]=r.useState(null);r.useLayoutEffect(()=>{if(!n)return;const I=()=>{const O=g.current,R=u.current;if(!O||!R)return;const w=O.getBoundingClientRect(),_=R.getBoundingClientRect(),c=Math.max(160,Math.min(h,window.innerWidth-a*2)),P=Math.min(_.width||c,c),L=_.height,A=J(w.left+w.width/2-P/2,a,window.innerWidth-P-a),b=J(w.top+w.height/2-L/2,a,window.innerHeight-L-a),T=w.top-L-e-H,x=w.bottom+e+H,p=w.left-P-e-H,E=w.right+e+H,C=T>=a,U=x+L<=window.innerHeight-a,S=p>=a,D=E+P<=window.innerWidth-a,y=()=>{const s=C||!U;return{top:s?Math.max(a,T):x,left:A,maxWidth:Math.min(c,h),placement:s?"top":"bottom"}},W=()=>{const s=D||!S;return{top:b,left:s?E:Math.max(a,p),maxWidth:Math.min(c,h),placement:s?"right":"left"}};if(o==="right"){m(D?{top:b,left:E,maxWidth:Math.min(c,h),placement:"right"}:S?{top:b,left:Math.max(a,p),maxWidth:Math.min(c,h),placement:"left"}:y());return}if(o==="left"){m(S?{top:b,left:Math.max(a,p),maxWidth:Math.min(c,h),placement:"left"}:D?{top:b,left:E,maxWidth:Math.min(c,h),placement:"right"}:y());return}if(o==="bottom"){m(U?{top:x,left:A,maxWidth:Math.min(c,h),placement:"bottom"}:C?{top:Math.max(a,T),left:A,maxWidth:Math.min(c,h),placement:"top"}:W());return}o==="top"&&m(C?{top:Math.max(a,T),left:A,maxWidth:Math.min(c,h),placement:"top"}:U?{top:x,left:A,maxWidth:Math.min(c,h),placement:"bottom"}:W())};return I(),window.addEventListener("resize",I),window.addEventListener("scroll",I,!0),()=>{window.removeEventListener("resize",I),window.removeEventListener("scroll",I,!0)}},[t,e,n,o]),r.useEffect(()=>{n||m(null)},[n]);const v=i?{position:"fixed",top:`${i.top}px`,left:`${i.left}px`,maxWidth:`${i.maxWidth}px`}:{position:"fixed",top:"-9999px",left:"-9999px",maxWidth:`min(${h}px, calc(100vw - ${a*2}px))`};return{triggerRef:g,tooltipRef:u,tooltipId:l,open:n,setOpen:d,tooltipStyle:v,placement:(i==null?void 0:i.placement)??"top"}}function mt({open:t,tooltipId:e,tooltipRef:o,tooltipStyle:g,content:u,customContent:l,placement:n,interactive:d,copyable:i,copied:m,onTooltipEnter:v,onTooltipLeave:I,onCopy:O}){if(!t)return null;const R=n==="top"?"absolute left-1/2 top-full h-0 w-0 -translate-x-1/2 border-x-[6px] border-t-[6px] border-x-transparent border-t-[var(--tooltip-surface)]":n==="bottom"?"absolute bottom-full left-1/2 h-0 w-0 -translate-x-1/2 border-x-[6px] border-b-[6px] border-x-transparent border-b-[var(--tooltip-surface)]":n==="right"?"absolute right-full top-1/2 h-0 w-0 -translate-y-1/2 border-y-[6px] border-r-[6px] border-y-transparent border-r-[var(--tooltip-surface)]":"absolute left-full top-1/2 h-0 w-0 -translate-y-1/2 border-y-[6px] border-l-[6px] border-y-transparent border-l-[var(--tooltip-surface)]";return nt.createPortal(f.jsx("div",{ref:o,id:e,role:"tooltip","data-placement":n,className:`${d?"pointer-events-auto":"pointer-events-none"} z-[1000]`,style:g,onMouseEnter:v,onMouseLeave:I,children:f.jsxs("div",{className:"relative whitespace-normal break-all rounded-lg bg-[var(--tooltip-surface)] px-3 py-2 text-xs leading-5 text-[var(--tooltip-text)] overflow-tooltip shadow-[var(--tooltip-shadow)]",children:[l||f.jsxs("div",{className:"flex items-center gap-1.5",children:[f.jsx("span",{className:`min-w-0 flex-1 ${i?"select-text":""}`,children:u}),i&&f.jsx("button",{type:"button",onClick:O,"aria-label":"复制",title:"复制",className:"inline-flex h-5 w-5 shrink-0 items-center justify-center rounded text-[var(--tooltip-icon)] transition-colors hover:text-[var(--tooltip-icon-hover)]",children:m?f.jsx("svg",{viewBox:"0 0 20 20",className:"h-3.5 w-3.5",fill:"none","aria-hidden":"true",children:f.jsx("path",{d:"M4.5 10.5L8 14l7.5-7.5",stroke:"currentColor",strokeWidth:"1.8",strokeLinecap:"round",strokeLinejoin:"round"})}):f.jsx("svg",{className:"h-3.5 w-3.5",viewBox:"0 0 1024 1024",version:"1.1",fill:"currentColor","aria-hidden":"true",children:f.jsx("path",{d:"M337.28 138.688a27.968 27.968 0 0 0-27.968 27.968v78.72h377.344c50.816 0 92.032 41.152 92.032 91.968v377.344h78.656a28.032 28.032 0 0 0 27.968-28.032V166.656a28.032 28.032 0 0 0-27.968-27.968H337.28z m441.408 640v78.656c0 50.816-41.216 91.968-92.032 91.968H166.656a92.032 92.032 0 0 1-91.968-91.968V337.28c0-50.816 41.152-92.032 91.968-92.032h78.72V166.656c0-50.816 41.152-91.968 91.968-91.968h520c50.816 0 91.968 41.152 91.968 91.968v520c0 50.816-41.152 92.032-91.968 92.032h-78.72zM166.656 309.312a27.968 27.968 0 0 0-27.968 28.032v520c0 15.424 12.544 27.968 27.968 27.968h520a28.032 28.032 0 0 0 28.032-27.968V337.28a28.032 28.032 0 0 0-28.032-28.032H166.656z","p-id":"5039"})})})]}),f.jsx("span",{"data-testid":"overflow-tooltip-arrow",className:R,"aria-hidden":"true"})]})}),document.body)}function wt(t){return t.scrollWidth>t.clientWidth||t.scrollHeight>t.clientHeight}function bt({content:t,customContent:e,className:o,textClassName:g,as:u="span",children:l,forceShow:n=!1,copyable:d=!1,gap:i=pt,placement:m="top"}){const v=r.useRef(null),{triggerRef:I,tooltipRef:O,tooltipId:R,open:w,setOpen:_,tooltipStyle:c,placement:P}=ht(t,i,m),L=d||!!e,[A,b]=r.useState(!1),T=r.useRef(null),x=r.useRef(null),p=r.useCallback(()=>{T.current!==null&&(window.clearTimeout(T.current),T.current=null)},[]),E=r.useCallback(()=>{x.current!==null&&(window.clearTimeout(x.current),x.current=null)},[]),C=r.useCallback(()=>{p(),T.current=window.setTimeout(()=>{_(!1),T.current=null},300)},[p,_]),U=r.useCallback(()=>{const s=v.current;if(!s)return;p(),(n||wt(s))&&(E(),x.current=window.setTimeout(()=>{_(!0),x.current=null},150))},[p,E,n,_]),S=r.useCallback(()=>{E(),L?C():_(!1)},[E,L,C,_]),D=r.useCallback(async()=>{if(!(!d||!t.trim()))try{await navigator.clipboard.writeText(t),b(!0),_(!0),window.setTimeout(()=>b(!1),1200)}catch{}},[t,d,_]);r.useEffect(()=>()=>{p(),E()},[p,E]);const y=(s,X)=>{if(s){if(typeof s=="function"){s(X);return}s.current=X}},W=l?r.isValidElement(l)?r.cloneElement(l,{ref:s=>{y(l.ref,s),v.current=s}}):l:r.cloneElement(f.jsx(u,{className:g,children:t}),{ref:v});return f.jsxs("div",{ref:I,className:o,onMouseEnter:U,onMouseLeave:S,onFocus:U,onBlur:S,"aria-describedby":w?R:void 0,children:[W,f.jsx(mt,{open:w,tooltipId:R,tooltipRef:O,tooltipStyle:c,content:t,customContent:e,placement:P,interactive:L,copyable:d,copied:A,onTooltipEnter:p,onTooltipLeave:C,onCopy:()=>void D()})]})}export{k as A,bt as O,Lt as a,It as b,$ as c,et as d,gt as e,Et as f,xt as g,Tt as h,tt as r};
|
|
2
|
+
//# sourceMappingURL=OverflowTooltip-CE5PjAb-.js.map
|