@nextclaw/ui 0.8.0 → 0.9.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.
Files changed (68) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/assets/ChannelsList-C7F_As4r.js +1 -0
  3. package/dist/assets/ChatPage-Oo7-OUsx.js +37 -0
  4. package/dist/assets/{DocBrowser-DDX2HMXW.js → DocBrowser-Dsd8Dlq8.js} +1 -1
  5. package/dist/assets/{LogoBadge-J53F_3JA.js → LogoBadge-2ChEc_oz.js} +1 -1
  6. package/dist/assets/{MarketplacePage-0BZ4bza0.js → MarketplacePage-BXck6-X3.js} +3 -3
  7. package/dist/assets/{ModelConfig-Wzq9wGHV.js → ModelConfig-CgHRSD0b.js} +1 -1
  8. package/dist/assets/ProvidersList-PPfZucvS.js +1 -0
  9. package/dist/assets/{RuntimeConfig-N771_AM6.js → RuntimeConfig-ClLEKNTN.js} +1 -1
  10. package/dist/assets/{SearchConfig-DVt5QVa_.js → SearchConfig-CuXVCbrf.js} +1 -1
  11. package/dist/assets/{SecretsConfig-CkwauPa8.js → SecretsConfig-udJz6Ake.js} +1 -1
  12. package/dist/assets/{SessionsConfig-C3mnHzkZ.js → SessionsConfig-C1XnFfiC.js} +2 -2
  13. package/dist/assets/{chat-message-pxr79GDs.js → chat-message-BETwXLD4.js} +1 -1
  14. package/dist/assets/{index-GdpEEKnz.js → index-COJdlL0e.js} +1 -1
  15. package/dist/assets/index-CsvP4CER.js +8 -0
  16. package/dist/assets/index-D-bXl7qL.css +1 -0
  17. package/dist/assets/{label-CmksBHgc.js → label-BGL-ztxh.js} +1 -1
  18. package/dist/assets/{page-layout-Db0GbnhS.js → page-layout-aw88k7tG.js} +1 -1
  19. package/dist/assets/popover-DyEvzhmV.js +1 -0
  20. package/dist/assets/{security-config-CjLFME5Q.js → security-config-BuPAQn82.js} +1 -1
  21. package/dist/assets/skeleton-drzO_tdU.js +1 -0
  22. package/dist/assets/{switch-C24d-UJU.js → switch-BK8jIzto.js} +1 -1
  23. package/dist/assets/tabs-custom-Da3cEOji.js +1 -0
  24. package/dist/assets/{useConfirmDialog-BeP35LcG.js → useConfirmDialog-z0CE92iS.js} +1 -1
  25. package/dist/assets/{vendor-psXJBy9u.js → vendor-CkJHmX1g.js} +1 -1
  26. package/dist/index.html +3 -3
  27. package/package.json +2 -2
  28. package/src/api/config.ts +9 -38
  29. package/src/api/ncp-session.ts +50 -0
  30. package/src/api/types.ts +1 -0
  31. package/src/components/chat/ChatConversationPanel.test.tsx +65 -0
  32. package/src/components/chat/ChatConversationPanel.tsx +21 -12
  33. package/src/components/chat/ChatSidebar.test.tsx +203 -0
  34. package/src/components/chat/ChatSidebar.tsx +97 -7
  35. package/src/components/chat/adapters/chat-message.adapter.test.ts +132 -82
  36. package/src/components/chat/adapters/chat-message.adapter.ts +27 -9
  37. package/src/components/chat/chat-page-data.ts +30 -1
  38. package/src/components/chat/chat-page-runtime.test.ts +181 -0
  39. package/src/components/chat/chat-page-runtime.ts +101 -15
  40. package/src/components/chat/chat-session-preference-sync.test.ts +62 -0
  41. package/src/components/chat/chat-session-preference-sync.ts +75 -0
  42. package/src/components/chat/containers/chat-input-bar.container.tsx +0 -22
  43. package/src/components/chat/containers/chat-message-list.container.tsx +31 -27
  44. package/src/components/chat/legacy/LegacyChatPage.tsx +24 -0
  45. package/src/components/chat/managers/chat-input.manager.ts +5 -0
  46. package/src/components/chat/managers/chat-session-list.manager.test.ts +39 -0
  47. package/src/components/chat/managers/chat-session-list.manager.ts +9 -3
  48. package/src/components/chat/ncp/NcpChatPage.tsx +42 -10
  49. package/src/components/chat/ncp/ncp-chat-input.manager.ts +6 -0
  50. package/src/components/chat/ncp/ncp-chat-page-data.ts +34 -2
  51. package/src/components/chat/ncp/ncp-chat-thread.manager.ts +1 -1
  52. package/src/components/chat/ncp/ncp-session-adapter.test.ts +27 -1
  53. package/src/components/chat/ncp/ncp-session-adapter.ts +20 -0
  54. package/src/components/chat/stores/chat-thread.store.ts +2 -0
  55. package/src/components/chat/useChatSessionTypeState.test.tsx +58 -0
  56. package/src/components/chat/useChatSessionTypeState.ts +25 -8
  57. package/src/hooks/use-ncp-chat-session-types.ts +11 -0
  58. package/src/hooks/useConfig.ts +2 -4
  59. package/src/hooks/useMarketplace.ts +7 -4
  60. package/src/hooks/useWebSocket.ts +23 -2
  61. package/dist/assets/ChannelsList-DBcoVJRW.js +0 -1
  62. package/dist/assets/ChatPage-CD3cxyyM.js +0 -37
  63. package/dist/assets/ProvidersList-kwzRS8_M.js +0 -1
  64. package/dist/assets/index-BIvFMkN4.js +0 -1
  65. package/dist/assets/index-CzkY1reu.js +0 -8
  66. package/dist/assets/index-RZ0kHHRI.css +0 -1
  67. package/dist/assets/skeleton-CkpQeVWN.js +0 -1
  68. package/dist/assets/tabs-custom-D89bh-fc.js +0 -1
@@ -1,4 +1,4 @@
1
- import { useEffect, useMemo } from 'react';
1
+ import { useEffect, useMemo, useRef } from 'react';
2
2
  import type { Dispatch, SetStateAction } from 'react';
3
3
  import type { SessionEntryView } from '@/api/types';
4
4
  import { t } from '@/lib/i18n';
@@ -33,13 +33,16 @@ export function resolveSessionTypeLabel(sessionType: string, fallbackLabel?: str
33
33
  if (sessionType === 'native') {
34
34
  return t('chatSessionTypeNative');
35
35
  }
36
- if (sessionType === 'codex-sdk') {
37
- return t('chatSessionTypeCodex');
36
+ const normalizedFallback = fallbackLabel?.trim();
37
+ if (normalizedFallback) {
38
+ return normalizedFallback;
38
39
  }
39
- if (sessionType === 'claude-agent-sdk') {
40
- return t('chatSessionTypeClaude');
41
- }
42
- return fallbackLabel?.trim() || sessionType;
40
+ return sessionType
41
+ .trim()
42
+ .split(/[-_]+/g)
43
+ .filter(Boolean)
44
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
45
+ .join(' ') || sessionType;
43
46
  }
44
47
 
45
48
  function buildSessionTypeOptions(
@@ -113,6 +116,7 @@ export function useChatSessionTypeState(params: UseChatSessionTypeStateParams):
113
116
  () => normalizeSessionType(sessionTypesData?.defaultType ?? DEFAULT_SESSION_TYPE),
114
117
  [sessionTypesData?.defaultType]
115
118
  );
119
+ const lastAutoPendingSessionTypeRef = useRef<string | null>(null);
116
120
  const selectedSessionType = useMemo(
117
121
  () => normalizeSessionType(selectedSession?.sessionType ?? pendingSessionType ?? defaultSessionType),
118
122
  [defaultSessionType, pendingSessionType, selectedSession?.sessionType]
@@ -122,8 +126,21 @@ export function useChatSessionTypeState(params: UseChatSessionTypeStateParams):
122
126
  if (selectedSessionKey) {
123
127
  return;
124
128
  }
129
+ const rawPending = typeof pendingSessionType === 'string' ? pendingSessionType.trim() : '';
130
+ const normalizedPending = normalizeSessionType(pendingSessionType);
131
+ const shouldFollowDefault =
132
+ rawPending.length === 0 ||
133
+ lastAutoPendingSessionTypeRef.current === normalizedPending ||
134
+ (lastAutoPendingSessionTypeRef.current === null && normalizedPending === DEFAULT_SESSION_TYPE);
135
+ if (!shouldFollowDefault) {
136
+ return;
137
+ }
138
+ lastAutoPendingSessionTypeRef.current = defaultSessionType;
139
+ if (normalizedPending === defaultSessionType) {
140
+ return;
141
+ }
125
142
  setPendingSessionType(defaultSessionType);
126
- }, [defaultSessionType, selectedSessionKey, setPendingSessionType]);
143
+ }, [defaultSessionType, pendingSessionType, selectedSessionKey, setPendingSessionType]);
127
144
 
128
145
  const canEditSessionType = !selectedSessionKey || Boolean(selectedSession?.sessionTypeMutable);
129
146
  const availableSessionTypeSet = useMemo(
@@ -0,0 +1,11 @@
1
+ import { useQuery } from '@tanstack/react-query';
2
+ import { fetchNcpChatSessionTypes } from '@/api/config';
3
+
4
+ export function useNcpChatSessionTypes() {
5
+ return useQuery({
6
+ queryKey: ['ncp-session-types'],
7
+ queryFn: fetchNcpChatSessionTypes,
8
+ staleTime: 10_000,
9
+ retry: false
10
+ });
11
+ }
@@ -19,11 +19,8 @@ import {
19
19
  executeConfigAction,
20
20
  fetchSessions,
21
21
  fetchSessionHistory,
22
- fetchNcpSessions,
23
- fetchNcpSessionMessages,
24
22
  updateSession,
25
23
  deleteSession,
26
- deleteNcpSession,
27
24
  sendChatTurn,
28
25
  fetchChatRun,
29
26
  fetchChatRuns,
@@ -34,6 +31,7 @@ import {
34
31
  setCronJobEnabled,
35
32
  runCronJob
36
33
  } from '@/api/config';
34
+ import { deleteNcpSession, fetchNcpSessionMessages, fetchNcpSessions } from '@/api/ncp-session';
37
35
  import { toast } from 'sonner';
38
36
  import { t } from '@/lib/i18n';
39
37
 
@@ -390,7 +388,7 @@ export function useChatRuns(params?: {
390
388
  if (params?.isLocallyRunning) {
391
389
  return 800;
392
390
  }
393
- const data = query.state.data;
391
+ const { data } = query.state;
394
392
  const hasActiveRuns = Array.isArray(data?.runs) && data.runs.length > 0;
395
393
  return hasActiveRuns ? 800 : false;
396
394
  },
@@ -61,8 +61,10 @@ export function useInstallMarketplaceItem() {
61
61
  mutationFn: (request: MarketplaceInstallRequest) => installMarketplaceItem(request),
62
62
  onSuccess: (result) => {
63
63
  queryClient.invalidateQueries({ queryKey: ['marketplace-installed', result.type] });
64
- queryClient.refetchQueries({ queryKey: ['marketplace-installed', result.type], type: 'active' });
65
- queryClient.refetchQueries({ queryKey: ['marketplace-items'], type: 'active' });
64
+ queryClient.invalidateQueries({ queryKey: ['marketplace-items'] });
65
+ if (result.type === 'plugin') {
66
+ queryClient.invalidateQueries({ queryKey: ['ncp-session-types'] });
67
+ }
66
68
  const fallback = result.type === 'plugin'
67
69
  ? t('marketplaceInstallSuccessPlugin')
68
70
  : t('marketplaceInstallSuccessSkill');
@@ -82,8 +84,9 @@ export function useManageMarketplaceItem() {
82
84
  onSuccess: (result) => {
83
85
  queryClient.invalidateQueries({ queryKey: ['marketplace-installed', result.type] });
84
86
  queryClient.invalidateQueries({ queryKey: ['marketplace-items'] });
85
- queryClient.refetchQueries({ queryKey: ['marketplace-installed', result.type], type: 'active' });
86
- queryClient.refetchQueries({ queryKey: ['marketplace-items'], type: 'active' });
87
+ if (result.type === 'plugin') {
88
+ queryClient.invalidateQueries({ queryKey: ['ncp-session-types'] });
89
+ }
87
90
  const fallback = result.action === 'enable'
88
91
  ? t('marketplaceEnableSuccess')
89
92
  : result.action === 'disable'
@@ -73,11 +73,25 @@ export function useWebSocket(queryClient?: QueryClient) {
73
73
  return;
74
74
  }
75
75
  queryClient.invalidateQueries({ queryKey: ['sessions'] });
76
+ queryClient.invalidateQueries({ queryKey: ['ncp-sessions'] });
76
77
  if (sessionKey && sessionKey.trim().length > 0) {
77
78
  queryClient.invalidateQueries({ queryKey: ['session-history', sessionKey.trim()] });
79
+ queryClient.invalidateQueries({ queryKey: ['ncp-session-messages', sessionKey.trim()] });
78
80
  return;
79
81
  }
80
82
  queryClient.invalidateQueries({ queryKey: ['session-history'] });
83
+ queryClient.invalidateQueries({ queryKey: ['ncp-session-messages'] });
84
+ };
85
+
86
+ const shouldInvalidateConfigQuery = (configPath: string) => {
87
+ const normalized = configPath.trim().toLowerCase();
88
+ if (!normalized) {
89
+ return true;
90
+ }
91
+ if (normalized.startsWith('plugins') || normalized.startsWith('skills')) {
92
+ return false;
93
+ }
94
+ return true;
81
95
  };
82
96
 
83
97
  setConnectionStatus('connecting');
@@ -98,13 +112,20 @@ export function useWebSocket(queryClient?: QueryClient) {
98
112
  });
99
113
 
100
114
  client.on('config.updated', (event) => {
115
+ const payload = event.payload as { path?: unknown } | undefined;
116
+ const configPath = typeof payload?.path === 'string' ? payload.path : '';
101
117
  // Trigger refetch of config
102
- if (queryClient) {
118
+ if (queryClient && shouldInvalidateConfigQuery(configPath)) {
103
119
  queryClient.invalidateQueries({ queryKey: ['config'] });
104
120
  }
105
- if (event.type === 'config.updated' && event.payload.path.startsWith('session')) {
121
+ if (configPath.startsWith('session')) {
106
122
  invalidateSessionQueries();
107
123
  }
124
+ if (configPath.startsWith('plugins')) {
125
+ queryClient?.invalidateQueries({ queryKey: ['ncp-session-types'] });
126
+ queryClient?.invalidateQueries({ queryKey: ['marketplace-installed', 'plugin'] });
127
+ queryClient?.invalidateQueries({ queryKey: ['marketplace-items'] });
128
+ }
108
129
  });
109
130
 
110
131
  client.on('run.updated', (event) => {
@@ -1 +0,0 @@
1
- import{r as v,j as a,a5 as Z,F as ee,e as T,K as ae,ah as te,aR as se,aS as ne,aT as le,z as re,s as oe,a8 as ce,v as ie}from"./vendor-psXJBy9u.js";import{t as e,c as I,Y as me,u as q,a as $,b as H,_ as pe,$ as de,I as D,S as be,e as ue,f as xe,g as ye,h as ge,B as E}from"./index-CzkY1reu.js";import{L as he}from"./label-CmksBHgc.js";import{S as fe}from"./switch-C24d-UJU.js";import{L as K,S as J}from"./LogoBadge-J53F_3JA.js";import{h as _}from"./config-hints-CApS3K_7.js";import{c as we,b as ve,a as je,C as ke}from"./config-layout-BHnOoweL.js";import{T as Se}from"./tabs-custom-D89bh-fc.js";import{P as Ce,a as Ne}from"./page-layout-Db0GbnhS.js";function Pe({value:t,onChange:m,className:i,placeholder:r=""}){const[o,u]=v.useState(""),d=x=>{x.key==="Enter"&&o.trim()?(x.preventDefault(),m([...t,o.trim()]),u("")):x.key==="Backspace"&&!o&&t.length>0&&m(t.slice(0,-1))},g=x=>{m(t.filter((j,h)=>h!==x))};return a.jsxs("div",{className:I("flex flex-wrap gap-2 p-2 border rounded-md min-h-[42px]",i),children:[t.map((x,j)=>a.jsxs("span",{className:"inline-flex items-center gap-1 px-2 py-1 bg-primary text-primary-foreground rounded text-sm",children:[x,a.jsx("button",{type:"button",onClick:()=>g(j),className:"hover:text-red-300 transition-colors",children:a.jsx(Z,{className:"h-3 w-3"})})]},j)),a.jsx("input",{type:"text",value:o,onChange:x=>u(x.target.value),onKeyDown:d,className:"flex-1 outline-none min-w-[100px] bg-transparent text-sm",placeholder:r||e("enterTag")})]})}function z(t){var r,o;const m=me();return((r=t.tutorialUrls)==null?void 0:r[m])||((o=t.tutorialUrls)==null?void 0:o.default)||t.tutorialUrl}const Ie={telegram:"telegram.svg",slack:"slack.svg",discord:"discord.svg",whatsapp:"whatsapp.svg",qq:"qq.svg",feishu:"feishu.svg",dingtalk:"dingtalk.svg",wecom:"wecom.svg",mochat:"mochat.svg",email:"email.svg"};function Fe(t,m){const i=m.toLowerCase(),r=t[i];return r?`/logos/${r}`:null}function Y(t){return Fe(Ie,t)}const R=[{value:"pairing",label:"pairing"},{value:"allowlist",label:"allowlist"},{value:"open",label:"open"},{value:"disabled",label:"disabled"}],B=[{value:"open",label:"open"},{value:"allowlist",label:"allowlist"},{value:"disabled",label:"disabled"}],Te=[{value:"off",label:"off"},{value:"partial",label:"partial"},{value:"block",label:"block"},{value:"progress",label:"progress"}],De=t=>t.includes("token")||t.includes("secret")||t.includes("password")?a.jsx(ae,{className:"h-3.5 w-3.5 text-gray-500"}):t.includes("url")||t.includes("host")?a.jsx(te,{className:"h-3.5 w-3.5 text-gray-500"}):t.includes("email")||t.includes("mail")?a.jsx(se,{className:"h-3.5 w-3.5 text-gray-500"}):t.includes("id")||t.includes("from")?a.jsx(ne,{className:"h-3.5 w-3.5 text-gray-500"}):t==="enabled"||t==="consentGranted"?a.jsx(le,{className:"h-3.5 w-3.5 text-gray-500"}):a.jsx(re,{className:"h-3.5 w-3.5 text-gray-500"});function G(){return{telegram:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"token",type:"password",label:e("botToken")},{name:"allowFrom",type:"tags",label:e("allowFrom")},{name:"proxy",type:"text",label:e("proxy")},{name:"accountId",type:"text",label:e("accountId")},{name:"dmPolicy",type:"select",label:e("dmPolicy"),options:R},{name:"groupPolicy",type:"select",label:e("groupPolicy"),options:B},{name:"groupAllowFrom",type:"tags",label:e("groupAllowFrom")},{name:"requireMention",type:"boolean",label:e("requireMention")},{name:"mentionPatterns",type:"tags",label:e("mentionPatterns")},{name:"groups",type:"json",label:e("groupRulesJson")}],discord:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"token",type:"password",label:e("botToken")},{name:"allowBots",type:"boolean",label:e("allowBotMessages")},{name:"allowFrom",type:"tags",label:e("allowFrom")},{name:"gatewayUrl",type:"text",label:e("gatewayUrl")},{name:"intents",type:"number",label:e("intents")},{name:"proxy",type:"text",label:e("proxy")},{name:"mediaMaxMb",type:"number",label:e("attachmentMaxSizeMb")},{name:"streaming",type:"select",label:e("streamingMode"),options:Te},{name:"draftChunk",type:"json",label:e("draftChunkingJson")},{name:"textChunkLimit",type:"number",label:e("textChunkLimit")},{name:"accountId",type:"text",label:e("accountId")},{name:"dmPolicy",type:"select",label:e("dmPolicy"),options:R},{name:"groupPolicy",type:"select",label:e("groupPolicy"),options:B},{name:"groupAllowFrom",type:"tags",label:e("groupAllowFrom")},{name:"requireMention",type:"boolean",label:e("requireMention")},{name:"mentionPatterns",type:"tags",label:e("mentionPatterns")},{name:"groups",type:"json",label:e("groupRulesJson")}],whatsapp:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"bridgeUrl",type:"text",label:e("bridgeUrl")},{name:"allowFrom",type:"tags",label:e("allowFrom")}],feishu:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"appId",type:"text",label:e("appId")},{name:"appSecret",type:"password",label:e("appSecret")},{name:"encryptKey",type:"password",label:e("encryptKey")},{name:"verificationToken",type:"password",label:e("verificationToken")},{name:"allowFrom",type:"tags",label:e("allowFrom")}],dingtalk:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"clientId",type:"text",label:e("clientId")},{name:"clientSecret",type:"password",label:e("clientSecret")},{name:"allowFrom",type:"tags",label:e("allowFrom")}],wecom:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"corpId",type:"text",label:e("corpId")},{name:"agentId",type:"text",label:e("agentId")},{name:"secret",type:"password",label:e("secret")},{name:"token",type:"password",label:e("token")},{name:"callbackPort",type:"number",label:e("callbackPort")},{name:"callbackPath",type:"text",label:e("callbackPath")},{name:"allowFrom",type:"tags",label:e("allowFrom")}],slack:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"mode",type:"text",label:e("mode")},{name:"webhookPath",type:"text",label:e("webhookPath")},{name:"allowBots",type:"boolean",label:e("allowBotMessages")},{name:"botToken",type:"password",label:e("botToken")},{name:"appToken",type:"password",label:e("appToken")}],email:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"consentGranted",type:"boolean",label:e("consentGranted")},{name:"imapHost",type:"text",label:e("imapHost")},{name:"imapPort",type:"number",label:e("imapPort")},{name:"imapUsername",type:"text",label:e("imapUsername")},{name:"imapPassword",type:"password",label:e("imapPassword")},{name:"fromAddress",type:"email",label:e("fromAddress")}],mochat:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"baseUrl",type:"text",label:e("baseUrl")},{name:"clawToken",type:"password",label:e("clawToken")},{name:"agentUserId",type:"text",label:e("agentUserId")},{name:"allowFrom",type:"tags",label:e("allowFrom")}],qq:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"appId",type:"text",label:e("appId")},{name:"secret",type:"password",label:e("appSecret")},{name:"markdownSupport",type:"boolean",label:e("markdownSupport")},{name:"allowFrom",type:"tags",label:e("allowFrom")}]}}function A(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function V(t,m){const i={...t};for(const[r,o]of Object.entries(m)){const u=i[r];if(A(u)&&A(o)){i[r]=V(u,o);continue}i[r]=o}return i}function Ae(t,m){const i=t.split("."),r={};let o=r;for(let u=0;u<i.length-1;u+=1){const d=i[u];o[d]={},o=o[d]}return o[i[i.length-1]]=m,r}function Le({channelName:t}){var O,U;const{data:m}=q(),{data:i}=$(),{data:r}=H(),o=pe(),u=de(),[d,g]=v.useState({}),[x,j]=v.useState({}),[h,f]=v.useState(null),k=t?m==null?void 0:m.channels[t]:null,w=t?G()[t]??[]:[],c=r==null?void 0:r.uiHints,p=t?`channels.${t}`:null,S=((O=r==null?void 0:r.actions)==null?void 0:O.filter(s=>s.scope===p))??[],C=t&&(((U=_(`channels.${t}`,c))==null?void 0:U.label)??t),P=i==null?void 0:i.channels.find(s=>s.name===t),F=P?z(P):void 0;v.useEffect(()=>{if(k){g({...k});const s={};(t?G()[t]??[]:[]).filter(l=>l.type==="json").forEach(l=>{const y=k[l.name];s[l.name]=JSON.stringify(y??{},null,2)}),j(s)}else g({}),j({})},[k,t]);const N=(s,n)=>{g(l=>({...l,[s]:n}))},L=s=>{if(s.preventDefault(),!t)return;const n={...d};for(const l of w){if(l.type!=="password")continue;const y=n[l.name];(typeof y!="string"||y.length===0)&&delete n[l.name]}for(const l of w){if(l.type!=="json")continue;const y=x[l.name]??"";try{n[l.name]=y.trim()?JSON.parse(y):{}}catch{T.error(`${e("invalidJson")}: ${l.name}`);return}}o.mutate({channel:t,data:n})},Q=s=>{if(!s||!t)return;const n=s.channels;if(!A(n))return;const l=n[t];A(l)&&g(y=>V(y,l))},W=async s=>{if(!(!t||!p)){f(s.id);try{let n={...d};s.saveBeforeRun&&(n={...n,...s.savePatch??{}},g(n),await o.mutateAsync({channel:t,data:n}));const l=await u.mutateAsync({actionId:s.id,data:{scope:p,draftConfig:Ae(p,n)}});Q(l.patch),l.ok?T.success(l.message||e("success")):T.error(l.message||e("error"))}catch(n){const l=n instanceof Error?n.message:String(n);T.error(`${e("error")}: ${l}`)}finally{f(null)}}};if(!t||!P||!k)return a.jsx("div",{className:we,children:a.jsxs("div",{children:[a.jsx("h3",{className:"text-base font-semibold text-gray-900",children:e("channelsSelectTitle")}),a.jsx("p",{className:"mt-2 text-sm text-gray-500",children:e("channelsSelectDescription")})]})});const M=!!k.enabled;return a.jsxs("div",{className:ve,children:[a.jsx("div",{className:"border-b border-gray-100 px-6 py-5",children:a.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[a.jsxs("div",{className:"min-w-0",children:[a.jsxs("div",{className:"flex items-center gap-3",children:[a.jsx(K,{name:t,src:Y(t),className:I("h-9 w-9 rounded-lg border",M?"border-primary/30 bg-white":"border-gray-200/70 bg-white"),imgClassName:"h-5 w-5 object-contain",fallback:a.jsx("span",{className:"text-sm font-semibold uppercase text-gray-500",children:t[0]})}),a.jsx("h3",{className:"truncate text-lg font-semibold text-gray-900 capitalize",children:C})]}),a.jsx("p",{className:"mt-2 text-sm text-gray-500",children:e("channelsFormDescription")}),F&&a.jsxs("a",{href:F,className:"mt-2 inline-flex items-center gap-1.5 text-xs text-primary transition-colors hover:text-primary-hover",children:[a.jsx(ee,{className:"h-3.5 w-3.5"}),e("channelsGuideTitle")]})]}),a.jsx(J,{status:M?"active":"inactive",label:M?e("statusActive"):e("statusInactive")})]})}),a.jsxs("form",{onSubmit:L,className:"flex min-h-0 flex-1 flex-col",children:[a.jsx("div",{className:"min-h-0 flex-1 space-y-6 overflow-y-auto overscroll-contain px-6 py-5",children:w.map(s=>{const n=t?_(`channels.${t}.${s.name}`,c):void 0,l=(n==null?void 0:n.label)??s.label,y=n==null?void 0:n.placeholder;return a.jsxs("div",{className:"space-y-2.5",children:[a.jsxs(he,{htmlFor:s.name,className:"flex items-center gap-2 text-sm font-medium text-gray-900",children:[De(s.name),l]}),s.type==="boolean"&&a.jsxs("div",{className:"flex items-center justify-between rounded-xl bg-gray-50 p-3",children:[a.jsx("span",{className:"text-sm text-gray-500",children:d[s.name]?e("enabled"):e("disabled")}),a.jsx(fe,{id:s.name,checked:d[s.name]||!1,onCheckedChange:b=>N(s.name,b),className:"data-[state=checked]:bg-emerald-500"})]}),(s.type==="text"||s.type==="email")&&a.jsx(D,{id:s.name,type:s.type,value:d[s.name]||"",onChange:b=>N(s.name,b.target.value),placeholder:y,className:"rounded-xl"}),s.type==="password"&&a.jsx(D,{id:s.name,type:"password",value:d[s.name]||"",onChange:b=>N(s.name,b.target.value),placeholder:y??e("leaveBlankToKeepUnchanged"),className:"rounded-xl"}),s.type==="number"&&a.jsx(D,{id:s.name,type:"number",value:d[s.name]||0,onChange:b=>N(s.name,parseInt(b.target.value,10)||0),placeholder:y,className:"rounded-xl"}),s.type==="tags"&&a.jsx(Pe,{value:d[s.name]||[],onChange:b=>N(s.name,b)}),s.type==="select"&&a.jsxs(be,{value:d[s.name]||"",onValueChange:b=>N(s.name,b),children:[a.jsx(ue,{className:"rounded-xl",children:a.jsx(xe,{})}),a.jsx(ye,{children:(s.options??[]).map(b=>a.jsx(ge,{value:b.value,children:b.label},b.value))})]}),s.type==="json"&&a.jsx("textarea",{id:s.name,value:x[s.name]??"{}",onChange:b=>j(X=>({...X,[s.name]:b.target.value})),className:"min-h-[120px] w-full resize-none rounded-lg border border-gray-200 bg-white px-3 py-2 text-xs font-mono"})]},s.name)})}),a.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3 border-t border-gray-100 px-6 py-4",children:[a.jsx("div",{className:"flex flex-wrap items-center gap-2",children:S.filter(s=>s.trigger==="manual").map(s=>a.jsx(E,{type:"button",onClick:()=>W(s),disabled:o.isPending||!!h,variant:"secondary",children:h===s.id?e("connecting"):s.title},s.id))}),a.jsx(E,{type:"submit",disabled:o.isPending||!!h,children:o.isPending?e("saving"):e("save")})]})]})]})}const Me={telegram:"channelDescTelegram",slack:"channelDescSlack",email:"channelDescEmail",webhook:"channelDescWebhook",discord:"channelDescDiscord",feishu:"channelDescFeishu"};function He(){const{data:t}=q(),{data:m}=$(),{data:i}=H(),[r,o]=v.useState("enabled"),[u,d]=v.useState(),[g,x]=v.useState(""),j=i==null?void 0:i.uiHints,h=m==null?void 0:m.channels,f=t==null?void 0:t.channels,k=[{id:"enabled",label:e("channelsTabEnabled"),count:(h??[]).filter(c=>{var p;return(p=f==null?void 0:f[c.name])==null?void 0:p.enabled}).length},{id:"all",label:e("channelsTabAll"),count:(h??[]).length}],w=v.useMemo(()=>{const c=g.trim().toLowerCase();return(h??[]).filter(p=>{var C;const S=((C=f==null?void 0:f[p.name])==null?void 0:C.enabled)||!1;return r==="enabled"?S:!0}).filter(p=>c?(p.displayName||p.name).toLowerCase().includes(c)||p.name.toLowerCase().includes(c):!0)},[r,f,h,g]);return v.useEffect(()=>{if(w.length===0){d(void 0);return}w.some(p=>p.name===u)||d(w[0].name)},[w,u]),!t||!m?a.jsx("div",{className:"p-8 text-gray-400",children:e("channelsLoading")}):a.jsxs(Ce,{className:"xl:flex xl:h-full xl:min-h-0 xl:flex-col xl:pb-0",children:[a.jsx(Ne,{title:e("channelsPageTitle"),description:e("channelsPageDescription")}),a.jsxs("div",{className:I(ke,"xl:min-h-0 xl:flex-1"),children:[a.jsxs("section",{className:je,children:[a.jsx("div",{className:"border-b border-gray-100 px-4 pt-4",children:a.jsx(Se,{tabs:k,activeTab:r,onChange:o,className:"mb-0"})}),a.jsx("div",{className:"border-b border-gray-100 px-4 py-3",children:a.jsxs("div",{className:"relative",children:[a.jsx(oe,{className:"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-gray-400"}),a.jsx(D,{value:g,onChange:c=>x(c.target.value),placeholder:e("channelsFilterPlaceholder"),className:"h-10 rounded-xl pl-9"})]})}),a.jsxs("div",{className:"min-h-0 flex-1 space-y-2 overflow-y-auto overscroll-contain p-3",children:[w.map(c=>{const p=t.channels[c.name],S=(p==null?void 0:p.enabled)||!1,C=_(`channels.${c.name}`,j),P=z(c),F=(C==null?void 0:C.help)||e(Me[c.name]||"channelDescriptionDefault"),N=u===c.name;return a.jsx("button",{type:"button",onClick:()=>d(c.name),className:I("w-full rounded-xl border p-2.5 text-left transition-all",N?"border-primary/30 bg-primary-50/40 shadow-sm":"border-gray-200/70 bg-white hover:border-gray-300 hover:bg-gray-50/70"),children:a.jsxs("div",{className:"flex items-start justify-between gap-3",children:[a.jsxs("div",{className:"flex min-w-0 items-center gap-3",children:[a.jsx(K,{name:c.name,src:Y(c.name),className:I("h-10 w-10 rounded-lg border",S?"border-primary/30 bg-white":"border-gray-200/70 bg-white"),imgClassName:"h-5 w-5 object-contain",fallback:a.jsx("span",{className:"text-sm font-semibold uppercase text-gray-500",children:c.name[0]})}),a.jsxs("div",{className:"min-w-0",children:[a.jsx("p",{className:"truncate text-sm font-semibold text-gray-900",children:c.displayName||c.name}),a.jsx("p",{className:"line-clamp-1 text-[11px] text-gray-500",children:F})]})]}),a.jsxs("div",{className:"flex items-center gap-2",children:[P&&a.jsx("a",{href:P,onClick:L=>L.stopPropagation(),className:"inline-flex h-7 w-7 items-center justify-center rounded-md text-gray-300 transition-colors hover:bg-gray-100/70 hover:text-gray-500",title:e("channelsGuideTitle"),children:a.jsx(ce,{className:"h-3.5 w-3.5"})}),a.jsx(J,{status:S?"active":"inactive",label:S?e("statusActive"):e("statusInactive"),className:"min-w-[56px] justify-center"})]})]})},c.name)}),w.length===0&&a.jsxs("div",{className:"flex h-full min-h-[220px] flex-col items-center justify-center rounded-xl border border-dashed border-gray-200 bg-gray-50/70 py-10 text-center",children:[a.jsx("div",{className:"mb-3 flex h-10 w-10 items-center justify-center rounded-lg bg-white",children:a.jsx(ie,{className:"h-5 w-5 text-gray-300"})}),a.jsx("p",{className:"text-sm font-medium text-gray-700",children:e("channelsNoMatch")})]})]})]}),a.jsx(Le,{channelName:u})]})]})}export{He as ChannelsList};