Compare commits
1 Commits
master
...
a5da34e1eb
| Author | SHA1 | Date | |
|---|---|---|---|
| a5da34e1eb |
@@ -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<TestDomainConnectionParams, boolean>(
|
||||
"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();
|
||||
|
||||
2
src/preload/index.d.ts
vendored
2
src/preload/index.d.ts
vendored
@@ -3,6 +3,7 @@ import type {
|
||||
Result,
|
||||
CreateDomainParams,
|
||||
UpdateDomainParams,
|
||||
TestDomainConnectionParams,
|
||||
GetSpacesParams,
|
||||
GetAppsParams,
|
||||
GetAppDetailParams,
|
||||
@@ -40,6 +41,7 @@ export interface ElectronAPI {
|
||||
updateDomain: (params: UpdateDomainParams) => Promise<Result<Domain>>;
|
||||
deleteDomain: (id: string) => Promise<Result<void>>;
|
||||
testConnection: (id: string) => Promise<Result<DomainWithStatus>>;
|
||||
testDomainConnection: (params: TestDomainConnectionParams) => Promise<Result<boolean>>;
|
||||
|
||||
// ==================== Browse ====================
|
||||
getSpaces: (params: GetSpacesParams) => Promise<Result<KintoneSpace[]>>;
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -64,11 +64,23 @@ const DomainForm: React.FC<DomainFormProps> = ({ 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<DomainFormProps> = ({ 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<DomainFormProps> = ({ 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 (
|
||||
<Modal
|
||||
@@ -128,12 +182,8 @@ const DomainForm: React.FC<DomainFormProps> = ({ open, onClose, domainId }) => {
|
||||
className={styles.form}
|
||||
initialValues={{ authType: "password" }}
|
||||
>
|
||||
<Form.Item
|
||||
name="name"
|
||||
label="名称"
|
||||
rules={[{ required: true, message: "请输入名称" }]}
|
||||
>
|
||||
<Input placeholder="例如:生产环境" />
|
||||
<Form.Item name="name" label="名称">
|
||||
<Input placeholder="可选,留空则使用域名" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
@@ -142,23 +192,35 @@ const DomainForm: React.FC<DomainFormProps> = ({ 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("请输入有效的域名"));
|
||||
},
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input placeholder="例如:company.kintone.com" />
|
||||
<Input placeholder="https://company.kintone.com" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name="username"
|
||||
label="用户名"
|
||||
rules={[
|
||||
{ required: true, message: "请输入用户名" },
|
||||
{ type: "email", message: "请输入有效的邮箱地址" },
|
||||
]}
|
||||
rules={[{ required: true, message: "请输入用户名" }]}
|
||||
>
|
||||
<Input placeholder="登录 Kintone 的邮箱地址" />
|
||||
<Input placeholder="登录 Kintone 的用户名" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
@@ -197,6 +259,9 @@ const DomainForm: React.FC<DomainFormProps> = ({ open, onClose, domainId }) => {
|
||||
<Form.Item style={{ marginTop: 24, marginBottom: 0 }}>
|
||||
<Space style={{ width: "100%", justifyContent: "flex-end" }}>
|
||||
<Button onClick={onClose}>取消</Button>
|
||||
<Button onClick={handleTestConnection} loading={testing}>
|
||||
测试连接
|
||||
</Button>
|
||||
<Button type="primary" onClick={handleSubmit} loading={loading}>
|
||||
{isEdit ? "更新" : "创建"}
|
||||
</Button>
|
||||
|
||||
@@ -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<Result<Domain>>;
|
||||
deleteDomain: (id: string) => Promise<Result<void>>;
|
||||
testConnection: (id: string) => Promise<Result<DomainWithStatus>>;
|
||||
testDomainConnection: (params: TestDomainConnectionParams) => Promise<Result<boolean>>;
|
||||
|
||||
// Browse
|
||||
getSpaces: (params: GetSpacesParams) => Promise<Result<KintoneSpace[]>>;
|
||||
|
||||
Reference in New Issue
Block a user