diff --git a/src/main/ipc-handlers.ts b/src/main/ipc-handlers.ts index bd0d401..9f3ed5f 100644 --- a/src/main/ipc-handlers.ts +++ b/src/main/ipc-handlers.ts @@ -24,6 +24,7 @@ import type { Result } from "@renderer/types/ipc"; import type { CreateDomainParams, UpdateDomainParams, + TestDomainConnectionParams, GetSpacesParams, GetAppsParams, GetAppDetailParams, @@ -206,6 +207,37 @@ function registerTestConnection(): void { }); } +/** + * Test domain connection with temporary credentials + */ +function registerTestDomainConnection(): void { + handleWithParams( + "testDomainConnection", + async (params) => { + const tempDomain: DomainWithPassword = { + id: "temp", + name: "temp", + domain: params.domain, + username: params.username, + password: params.password || "", + authType: params.authType, + apiToken: params.apiToken, + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + }; + + const client = new KintoneClient(tempDomain); + const result = await client.testConnection(); + + if (!result.success) { + throw new Error(result.error || "Connection failed"); + } + + return true; + }, + ); +} + // ==================== Browse IPC Handlers ==================== /** @@ -521,6 +553,7 @@ export function registerIpcHandlers(): void { registerUpdateDomain(); registerDeleteDomain(); registerTestConnection(); + registerTestDomainConnection(); // Browse registerGetSpaces(); diff --git a/src/preload/index.d.ts b/src/preload/index.d.ts index a41aa03..d411a8e 100644 --- a/src/preload/index.d.ts +++ b/src/preload/index.d.ts @@ -3,6 +3,7 @@ import type { Result, CreateDomainParams, UpdateDomainParams, + TestDomainConnectionParams, GetSpacesParams, GetAppsParams, GetAppDetailParams, @@ -40,6 +41,7 @@ export interface ElectronAPI { updateDomain: (params: UpdateDomainParams) => Promise>; deleteDomain: (id: string) => Promise>; testConnection: (id: string) => Promise>; + testDomainConnection: (params: TestDomainConnectionParams) => Promise>; // ==================== Browse ==================== getSpaces: (params: GetSpacesParams) => Promise>; diff --git a/src/preload/index.ts b/src/preload/index.ts index 30396ae..23df7e0 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -13,6 +13,7 @@ const api: ElectronAPI = { updateDomain: (params) => ipcRenderer.invoke("updateDomain", params), deleteDomain: (id) => ipcRenderer.invoke("deleteDomain", id), testConnection: (id) => ipcRenderer.invoke("testConnection", id), + testDomainConnection: (params) => ipcRenderer.invoke("testDomainConnection", params), // ==================== Browse ==================== getSpaces: (params) => ipcRenderer.invoke("getSpaces", params), diff --git a/src/renderer/src/components/DomainManager/DomainForm.tsx b/src/renderer/src/components/DomainManager/DomainForm.tsx index 292696c..3129f52 100644 --- a/src/renderer/src/components/DomainManager/DomainForm.tsx +++ b/src/renderer/src/components/DomainManager/DomainForm.tsx @@ -64,11 +64,23 @@ const DomainForm: React.FC = ({ open, onClose, domainId }) => { try { const values = await form.validateFields(); + // Process domain: remove protocol prefix and trailing slashes + let processedDomain = values.domain.trim(); + if (processedDomain.startsWith("https://")) { + processedDomain = processedDomain.slice(8); + } else if (processedDomain.startsWith("http://")) { + processedDomain = processedDomain.slice(7); + } + processedDomain = processedDomain.replace(/\/+$/, ""); + + // Use domain as name if name is empty + const name = values.name?.trim() || processedDomain; + if (isEdit && editingDomain) { const params: UpdateDomainParams = { id: domainId, - name: values.name, - domain: values.domain, + name, + domain: processedDomain, username: values.username, authType: values.authType, apiToken: @@ -89,8 +101,8 @@ const DomainForm: React.FC = ({ open, onClose, domainId }) => { } } else { const params: CreateDomainParams = { - name: values.name, - domain: values.domain, + name, + domain: processedDomain, username: values.username, password: values.password, authType: values.authType, @@ -112,6 +124,48 @@ const DomainForm: React.FC = ({ open, onClose, domainId }) => { }; const authType = Form.useWatch("authType", form); + const [testing, setTesting] = React.useState(false); + + // Test connection with current form values + const handleTestConnection = async () => { + try { + const values = await form.validateFields([ + "domain", + "username", + "authType", + "password", + "apiToken", + ]); + + // Process domain + let processedDomain = values.domain.trim(); + if (processedDomain.startsWith("https://")) { + processedDomain = processedDomain.slice(8); + } else if (processedDomain.startsWith("http://")) { + processedDomain = processedDomain.slice(7); + } + processedDomain = processedDomain.replace(/\/+$/, ""); + + setTesting(true); + const result = await window.api.testDomainConnection({ + domain: processedDomain, + username: values.username, + authType: values.authType, + password: values.authType === "password" ? values.password : undefined, + apiToken: values.authType === "api_token" ? values.apiToken : undefined, + }); + + if (result.success) { + message.success("连接成功"); + } else { + message.error(result.error || "连接失败"); + } + } catch (error) { + console.error("Test connection failed:", error); + } finally { + setTesting(false); + } + }; return ( = ({ open, onClose, domainId }) => { className={styles.form} initialValues={{ authType: "password" }} > - - + + = ({ open, onClose, domainId }) => { rules={[ { required: true, message: "请输入域名" }, { - pattern: /^[\w.-]+$/, - message: "请输入有效的域名,例如:company.kintone.com", + validator: (_, value) => { + if (!value) return Promise.resolve(); + // Allow https:// or http:// prefix + let domain = value.trim(); + if (domain.startsWith("https://")) { + domain = domain.slice(8); + } else if (domain.startsWith("http://")) { + domain = domain.slice(7); + } + // Remove trailing slashes + domain = domain.replace(/\/+$/, ""); + // Validate domain format + if (/^[\w.-]+$/.test(domain)) { + return Promise.resolve(); + } + return Promise.reject(new Error("请输入有效的域名")); + }, }, ]} > - + - + = ({ open, onClose, domainId }) => { + diff --git a/src/renderer/src/types/ipc.ts b/src/renderer/src/types/ipc.ts index fd4c6ef..1c0e910 100644 --- a/src/renderer/src/types/ipc.ts +++ b/src/renderer/src/types/ipc.ts @@ -38,6 +38,14 @@ export interface UpdateDomainParams { apiToken?: string; } +export interface TestDomainConnectionParams { + domain: string; + username: string; + authType: "password" | "api_token"; + password?: string; + apiToken?: string; +} + // ==================== Browse IPC Types ==================== export interface GetSpacesParams { @@ -126,6 +134,7 @@ export interface ElectronAPI { updateDomain: (params: UpdateDomainParams) => Promise>; deleteDomain: (id: string) => Promise>; testConnection: (id: string) => Promise>; + testDomainConnection: (params: TestDomainConnectionParams) => Promise>; // Browse getSpaces: (params: GetSpacesParams) => Promise>;