remove api token auth
This commit is contained in:
@@ -19,7 +19,6 @@ const TEST_CONFIG: DomainWithPassword = {
|
|||||||
domain: "alicorn.cybozu.com",
|
domain: "alicorn.cybozu.com",
|
||||||
username: "maxz",
|
username: "maxz",
|
||||||
password: "7ld7i8vd",
|
password: "7ld7i8vd",
|
||||||
authType: "password",
|
|
||||||
createdAt: new Date().toISOString(),
|
createdAt: new Date().toISOString(),
|
||||||
updatedAt: new Date().toISOString(),
|
updatedAt: new Date().toISOString(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -124,8 +124,6 @@ function registerCreateDomain(): void {
|
|||||||
name: params.name,
|
name: params.name,
|
||||||
domain: params.domain,
|
domain: params.domain,
|
||||||
username: params.username,
|
username: params.username,
|
||||||
authType: params.authType,
|
|
||||||
apiToken: params.apiToken,
|
|
||||||
createdAt: now,
|
createdAt: now,
|
||||||
updatedAt: now,
|
updatedAt: now,
|
||||||
};
|
};
|
||||||
@@ -152,8 +150,6 @@ function registerUpdateDomain(): void {
|
|||||||
name: params.name ?? existing.name,
|
name: params.name ?? existing.name,
|
||||||
domain: params.domain ?? existing.domain,
|
domain: params.domain ?? existing.domain,
|
||||||
username: params.username ?? existing.username,
|
username: params.username ?? existing.username,
|
||||||
authType: params.authType ?? existing.authType,
|
|
||||||
apiToken: params.apiToken ?? existing.apiToken,
|
|
||||||
updatedAt: new Date().toISOString(),
|
updatedAt: new Date().toISOString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -219,8 +215,6 @@ function registerTestDomainConnection(): void {
|
|||||||
domain: params.domain,
|
domain: params.domain,
|
||||||
username: params.username,
|
username: params.username,
|
||||||
password: params.password || "",
|
password: params.password || "",
|
||||||
authType: params.authType,
|
|
||||||
apiToken: params.apiToken,
|
|
||||||
createdAt: new Date().toISOString(),
|
createdAt: new Date().toISOString(),
|
||||||
updatedAt: new Date().toISOString(),
|
updatedAt: new Date().toISOString(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { KintoneRestAPIClient } from '@kintone/rest-api-client';
|
import { KintoneRestAPIClient } from "@kintone/rest-api-client";
|
||||||
import type { KintoneRestAPIError } from '@kintone/rest-api-client';
|
import type { KintoneRestAPIError } from "@kintone/rest-api-client";
|
||||||
import type { DomainWithPassword } from '@shared/types/domain';
|
import type { DomainWithPassword } from "@shared/types/domain";
|
||||||
import {
|
import {
|
||||||
type AppResponse,
|
type AppResponse,
|
||||||
type AppDetail,
|
type AppDetail,
|
||||||
type FileContent,
|
type FileContent,
|
||||||
type KintoneApiError,
|
type KintoneApiError,
|
||||||
AppCustomizeParameter,
|
AppCustomizeParameter,
|
||||||
} from '@shared/types/kintone';
|
} from "@shared/types/kintone";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom error class for Kintone API errors
|
* Custom error class for Kintone API errors
|
||||||
@@ -17,9 +17,13 @@ export class KintoneError extends Error {
|
|||||||
public readonly id?: string;
|
public readonly id?: string;
|
||||||
public readonly statusCode?: number;
|
public readonly statusCode?: number;
|
||||||
|
|
||||||
constructor(message: string, apiError?: KintoneApiError, statusCode?: number) {
|
constructor(
|
||||||
|
message: string,
|
||||||
|
apiError?: KintoneApiError,
|
||||||
|
statusCode?: number,
|
||||||
|
) {
|
||||||
super(message);
|
super(message);
|
||||||
this.name = 'KintoneError';
|
this.name = "KintoneError";
|
||||||
this.code = apiError?.code;
|
this.code = apiError?.code;
|
||||||
this.id = apiError?.id;
|
this.id = apiError?.id;
|
||||||
this.statusCode = statusCode;
|
this.statusCode = statusCode;
|
||||||
@@ -36,22 +40,17 @@ export class KintoneClient {
|
|||||||
constructor(domainConfig: DomainWithPassword) {
|
constructor(domainConfig: DomainWithPassword) {
|
||||||
this.domain = domainConfig.domain;
|
this.domain = domainConfig.domain;
|
||||||
|
|
||||||
const auth =
|
|
||||||
domainConfig.authType === 'api_token'
|
|
||||||
? { apiToken: domainConfig.apiToken || '' }
|
|
||||||
: {
|
|
||||||
username: domainConfig.username,
|
|
||||||
password: domainConfig.password,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.client = new KintoneRestAPIClient({
|
this.client = new KintoneRestAPIClient({
|
||||||
baseUrl: `https://${domainConfig.domain}`,
|
baseUrl: `https://${domainConfig.domain}`,
|
||||||
auth,
|
auth: {
|
||||||
|
username: domainConfig.username,
|
||||||
|
password: domainConfig.password,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private convertError(error: unknown): KintoneError {
|
private convertError(error: unknown): KintoneError {
|
||||||
if (error && typeof error === 'object' && 'code' in error) {
|
if (error && typeof error === "object" && "code" in error) {
|
||||||
const apiError = error as KintoneRestAPIError;
|
const apiError = error as KintoneRestAPIError;
|
||||||
return new KintoneError(
|
return new KintoneError(
|
||||||
apiError.message,
|
apiError.message,
|
||||||
@@ -64,7 +63,7 @@ export class KintoneClient {
|
|||||||
return new KintoneError(error.message);
|
return new KintoneError(error.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new KintoneError('Unknown error occurred');
|
return new KintoneError("Unknown error occurred");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async withErrorHandling<T>(operation: () => Promise<T>): Promise<T> {
|
private async withErrorHandling<T>(operation: () => Promise<T>): Promise<T> {
|
||||||
@@ -81,7 +80,10 @@ export class KintoneClient {
|
|||||||
* Get all apps with pagination support
|
* Get all apps with pagination support
|
||||||
* Fetches all apps by making multiple requests if needed
|
* Fetches all apps by making multiple requests if needed
|
||||||
*/
|
*/
|
||||||
async getApps(options?: { limit?: number; offset?: number }): Promise<AppResponse[]> {
|
async getApps(options?: {
|
||||||
|
limit?: number;
|
||||||
|
offset?: number;
|
||||||
|
}): Promise<AppResponse[]> {
|
||||||
return this.withErrorHandling(async () => {
|
return this.withErrorHandling(async () => {
|
||||||
// If pagination options provided, use them directly
|
// If pagination options provided, use them directly
|
||||||
if (options?.limit !== undefined || options?.offset !== undefined) {
|
if (options?.limit !== undefined || options?.offset !== undefined) {
|
||||||
@@ -134,19 +136,23 @@ export class KintoneClient {
|
|||||||
return this.withErrorHandling(async () => {
|
return this.withErrorHandling(async () => {
|
||||||
const data = await this.client.file.downloadFile({ fileKey });
|
const data = await this.client.file.downloadFile({ fileKey });
|
||||||
const buffer = Buffer.from(data);
|
const buffer = Buffer.from(data);
|
||||||
const content = buffer.toString('base64');
|
const content = buffer.toString("base64");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
fileKey,
|
fileKey,
|
||||||
name: fileKey,
|
name: fileKey,
|
||||||
size: buffer.byteLength,
|
size: buffer.byteLength,
|
||||||
mimeType: 'application/octet-stream',
|
mimeType: "application/octet-stream",
|
||||||
content,
|
content,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async uploadFile(content: string | Buffer, fileName: string, _mimeType?: string): Promise<{ fileKey: string }> {
|
async uploadFile(
|
||||||
|
content: string | Buffer,
|
||||||
|
fileName: string,
|
||||||
|
_mimeType?: string,
|
||||||
|
): Promise<{ fileKey: string }> {
|
||||||
return this.withErrorHandling(async () => {
|
return this.withErrorHandling(async () => {
|
||||||
const response = await this.client.file.uploadFile({
|
const response = await this.client.file.uploadFile({
|
||||||
file: { name: fileName, data: content },
|
file: { name: fileName, data: content },
|
||||||
@@ -157,7 +163,10 @@ export class KintoneClient {
|
|||||||
|
|
||||||
// ==================== Deploy APIs ====================
|
// ==================== Deploy APIs ====================
|
||||||
|
|
||||||
async updateAppCustomize(appId: string, config: Omit<AppCustomizeParameter, 'app'>): Promise<void> {
|
async updateAppCustomize(
|
||||||
|
appId: string,
|
||||||
|
config: Omit<AppCustomizeParameter, "app">,
|
||||||
|
): Promise<void> {
|
||||||
return this.withErrorHandling(async () => {
|
return this.withErrorHandling(async () => {
|
||||||
await this.client.app.updateAppCustomize({ ...config, app: appId });
|
await this.client.app.updateAppCustomize({ ...config, app: appId });
|
||||||
});
|
});
|
||||||
@@ -169,10 +178,12 @@ export class KintoneClient {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDeployStatus(appId: string): Promise<'PROCESSING' | 'SUCCESS' | 'FAIL' | 'CANCEL'> {
|
async getDeployStatus(
|
||||||
|
appId: string,
|
||||||
|
): Promise<"PROCESSING" | "SUCCESS" | "FAIL" | "CANCEL"> {
|
||||||
return this.withErrorHandling(async () => {
|
return this.withErrorHandling(async () => {
|
||||||
const response = await this.client.app.getDeployStatus({ apps: [appId] });
|
const response = await this.client.app.getDeployStatus({ apps: [appId] });
|
||||||
return response.apps[0]?.status || 'FAIL';
|
return response.apps[0]?.status || "FAIL";
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +197,8 @@ export class KintoneClient {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
error: error instanceof KintoneError ? error.message : 'Connection failed',
|
error:
|
||||||
|
error instanceof KintoneError ? error.message : "Connection failed",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ import { createStyles } from "antd-style";
|
|||||||
import { useAppStore } from "@renderer/stores";
|
import { useAppStore } from "@renderer/stores";
|
||||||
import { useDomainStore } from "@renderer/stores";
|
import { useDomainStore } from "@renderer/stores";
|
||||||
import { CodeViewer } from "../CodeViewer";
|
import { CodeViewer } from "../CodeViewer";
|
||||||
import { FileConfigResponse } from "@shared/types/kintone";
|
import { FileConfigResponse, isFileResource } from "@shared/types/kintone";
|
||||||
import { getDisplayName, getFileKey, isFileUpload } from "@shared/utils/fileDisplay";
|
import { getDisplayName, getFileKey } from "@shared/utils/fileDisplay";
|
||||||
const useStyles = createStyles(({ token, css }) => ({
|
const useStyles = createStyles(({ token, css }) => ({
|
||||||
container: css`
|
container: css`
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -180,7 +180,7 @@ const AppDetail: React.FC = () => {
|
|||||||
{files.map((file, index) => {
|
{files.map((file, index) => {
|
||||||
const fileName = getDisplayName(file, type, index);
|
const fileName = getDisplayName(file, type, index);
|
||||||
const fileKey = getFileKey(file);
|
const fileKey = getFileKey(file);
|
||||||
const canView = isFileUpload(file);
|
const canView = isFileResource(file);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -4,13 +4,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Modal, Form, Input, Select, Button, Space, message } from "antd";
|
import { Modal, Form, Input, Button, Space, message } from "antd";
|
||||||
import { createStyles } from "antd-style";
|
import { createStyles } from "antd-style";
|
||||||
import { useDomainStore } from "@renderer/stores";
|
import { useDomainStore } from "@renderer/stores";
|
||||||
import type {
|
import type { CreateDomainParams, UpdateDomainParams } from "@shared/types/ipc";
|
||||||
CreateDomainParams,
|
|
||||||
UpdateDomainParams,
|
|
||||||
} from "@shared/types/ipc";
|
|
||||||
|
|
||||||
const useStyles = createStyles(({ token, css }) => ({
|
const useStyles = createStyles(({ token, css }) => ({
|
||||||
form: css`
|
form: css`
|
||||||
@@ -49,12 +46,9 @@ const DomainForm: React.FC<DomainFormProps> = ({ open, onClose, domainId }) => {
|
|||||||
name: editingDomain.name,
|
name: editingDomain.name,
|
||||||
domain: editingDomain.domain,
|
domain: editingDomain.domain,
|
||||||
username: editingDomain.username,
|
username: editingDomain.username,
|
||||||
authType: editingDomain.authType,
|
|
||||||
apiToken: editingDomain.apiToken || "",
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
form.setFieldsValue({ authType: "password" });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [open, editingDomain, form]);
|
}, [open, editingDomain, form]);
|
||||||
@@ -81,9 +75,6 @@ const DomainForm: React.FC<DomainFormProps> = ({ open, onClose, domainId }) => {
|
|||||||
name,
|
name,
|
||||||
domain: processedDomain,
|
domain: processedDomain,
|
||||||
username: values.username,
|
username: values.username,
|
||||||
authType: values.authType,
|
|
||||||
apiToken:
|
|
||||||
values.authType === "api_token" ? values.apiToken : undefined,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Only include password if provided
|
// Only include password if provided
|
||||||
@@ -104,9 +95,6 @@ const DomainForm: React.FC<DomainFormProps> = ({ open, onClose, domainId }) => {
|
|||||||
domain: processedDomain,
|
domain: processedDomain,
|
||||||
username: values.username,
|
username: values.username,
|
||||||
password: values.password,
|
password: values.password,
|
||||||
authType: values.authType,
|
|
||||||
apiToken:
|
|
||||||
values.authType === "api_token" ? values.apiToken : undefined,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const success = await createDomain(params);
|
const success = await createDomain(params);
|
||||||
@@ -122,7 +110,6 @@ const DomainForm: React.FC<DomainFormProps> = ({ open, onClose, domainId }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const authType = Form.useWatch("authType", form);
|
|
||||||
const [testing, setTesting] = React.useState(false);
|
const [testing, setTesting] = React.useState(false);
|
||||||
|
|
||||||
// Test connection with current form values
|
// Test connection with current form values
|
||||||
@@ -131,9 +118,7 @@ const DomainForm: React.FC<DomainFormProps> = ({ open, onClose, domainId }) => {
|
|||||||
const values = await form.validateFields([
|
const values = await form.validateFields([
|
||||||
"domain",
|
"domain",
|
||||||
"username",
|
"username",
|
||||||
"authType",
|
|
||||||
"password",
|
"password",
|
||||||
"apiToken",
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Process domain
|
// Process domain
|
||||||
@@ -149,9 +134,7 @@ const DomainForm: React.FC<DomainFormProps> = ({ open, onClose, domainId }) => {
|
|||||||
const result = await window.api.testDomainConnection({
|
const result = await window.api.testDomainConnection({
|
||||||
domain: processedDomain,
|
domain: processedDomain,
|
||||||
username: values.username,
|
username: values.username,
|
||||||
authType: values.authType,
|
password: values.password,
|
||||||
password: values.authType === "password" ? values.password : undefined,
|
|
||||||
apiToken: values.authType === "api_token" ? values.apiToken : undefined,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
@@ -175,17 +158,11 @@ const DomainForm: React.FC<DomainFormProps> = ({ open, onClose, domainId }) => {
|
|||||||
width={520}
|
width={520}
|
||||||
destroyOnClose
|
destroyOnClose
|
||||||
>
|
>
|
||||||
<Form
|
<Form form={form} layout="vertical" className={styles.form}>
|
||||||
form={form}
|
|
||||||
layout="vertical"
|
|
||||||
className={styles.form}
|
|
||||||
initialValues={{ authType: "password" }}
|
|
||||||
>
|
|
||||||
<Form.Item name="name" label="名称" style={{ marginTop: 8 }}>
|
<Form.Item name="name" label="名称" style={{ marginTop: 8 }}>
|
||||||
<Input placeholder="可选,留空则使用域名" />
|
<Input placeholder="可选,留空则使用域名" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="domain"
|
name="domain"
|
||||||
label="Kintone 域名"
|
label="Kintone 域名"
|
||||||
@@ -224,38 +201,15 @@ const DomainForm: React.FC<DomainFormProps> = ({ open, onClose, domainId }) => {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="authType"
|
name="password"
|
||||||
label="认证方式"
|
label="密码"
|
||||||
rules={[{ required: true }]}
|
rules={isEdit ? [] : [{ required: true, message: "请输入密码" }]}
|
||||||
>
|
>
|
||||||
<Select>
|
<Input.Password
|
||||||
<Select.Option value="password">密码认证</Select.Option>
|
placeholder={isEdit ? "留空则保持原密码" : "请输入密码"}
|
||||||
<Select.Option value="api_token">API Token 认证</Select.Option>
|
/>
|
||||||
</Select>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
{authType === "password" && (
|
|
||||||
<Form.Item
|
|
||||||
name="password"
|
|
||||||
label="密码"
|
|
||||||
rules={isEdit ? [] : [{ required: true, message: "请输入密码" }]}
|
|
||||||
>
|
|
||||||
<Input.Password
|
|
||||||
placeholder={isEdit ? "留空则保持原密码" : "请输入密码"}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{authType === "api_token" && (
|
|
||||||
<Form.Item
|
|
||||||
name="apiToken"
|
|
||||||
label="API Token"
|
|
||||||
rules={[{ required: true, message: "请输入 API Token" }]}
|
|
||||||
>
|
|
||||||
<Input placeholder="从 Kintone 设置中获取 API Token" />
|
|
||||||
</Form.Item>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<Form.Item style={{ marginTop: 24, marginBottom: 0 }}>
|
<Form.Item style={{ marginTop: 24, marginBottom: 0 }}>
|
||||||
<Space style={{ width: "100%", justifyContent: "flex-end" }}>
|
<Space style={{ width: "100%", justifyContent: "flex-end" }}>
|
||||||
<Button onClick={onClose}>取消</Button>
|
<Button onClick={onClose}>取消</Button>
|
||||||
|
|||||||
@@ -4,11 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import type { Domain, DomainWithStatus } from "./domain";
|
import type { Domain, DomainWithStatus } from "./domain";
|
||||||
import type {
|
import type { AppResponse, AppDetail, FileContent } from "./kintone";
|
||||||
AppResponse,
|
|
||||||
AppDetail,
|
|
||||||
FileContent,
|
|
||||||
} from "./kintone";
|
|
||||||
import type { Version, DownloadMetadata, BackupMetadata } from "./version";
|
import type { Version, DownloadMetadata, BackupMetadata } from "./version";
|
||||||
|
|
||||||
// Unified result type
|
// Unified result type
|
||||||
@@ -23,8 +19,6 @@ export interface CreateDomainParams {
|
|||||||
domain: string;
|
domain: string;
|
||||||
username: string;
|
username: string;
|
||||||
password: string;
|
password: string;
|
||||||
authType: "password" | "api_token";
|
|
||||||
apiToken?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdateDomainParams {
|
export interface UpdateDomainParams {
|
||||||
@@ -33,16 +27,12 @@ export interface UpdateDomainParams {
|
|||||||
domain?: string;
|
domain?: string;
|
||||||
username?: string;
|
username?: string;
|
||||||
password?: string;
|
password?: string;
|
||||||
authType?: "password" | "api_token";
|
|
||||||
apiToken?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TestDomainConnectionParams {
|
export interface TestDomainConnectionParams {
|
||||||
domain: string;
|
domain: string;
|
||||||
username: string;
|
username: string;
|
||||||
authType: "password" | "api_token";
|
password: string;
|
||||||
password?: string;
|
|
||||||
apiToken?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== Browse IPC Types ====================
|
// ==================== Browse IPC Types ====================
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ export type FileResourceResponse = ExtractFileType<FileConfigResponse>;
|
|||||||
export function isUrlResource(
|
export function isUrlResource(
|
||||||
resource: FileConfigResponse | FileConfigParameter,
|
resource: FileConfigResponse | FileConfigParameter,
|
||||||
): resource is UrlResourceParameter | UrlResourceResponse {
|
): resource is UrlResourceParameter | UrlResourceResponse {
|
||||||
return resource.type === "URL";
|
return resource.type === "URL" && !!resource.url;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -96,5 +96,5 @@ export function isUrlResource(
|
|||||||
export function isFileResource(
|
export function isFileResource(
|
||||||
resource: FileConfigResponse | FileConfigParameter,
|
resource: FileConfigResponse | FileConfigParameter,
|
||||||
): resource is FileResourceParameter | FileResourceResponse {
|
): resource is FileResourceParameter | FileResourceResponse {
|
||||||
return resource.type === "FILE";
|
return resource.type === "FILE" && !!resource.file?.fileKey;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { FileConfigResponse } from "@shared/types/kintone";
|
import { isFileResource, isUrlResource, type FileConfigResponse } from "@shared/types/kintone";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get user-friendly display name for a file config
|
* Get user-friendly display name for a file config
|
||||||
@@ -8,11 +8,11 @@ export function getDisplayName(
|
|||||||
fileType: "js" | "css",
|
fileType: "js" | "css",
|
||||||
index: number,
|
index: number,
|
||||||
): string {
|
): string {
|
||||||
if (file.type === "URL" && file.url) {
|
if (isUrlResource(file)) {
|
||||||
return extractFilenameFromUrl(file.url) || `URL ${index + 1}`;
|
return extractFilenameFromUrl(file.url) || `URL ${index + 1}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file.type === "FILE" && file.file?.fileKey) {
|
if (isFileResource(file)) {
|
||||||
return `${file.file.fileKey}.${fileType}`;
|
return `${file.file.fileKey}.${fileType}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,16 +33,9 @@ export function extractFilenameFromUrl(url: string): string | null {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if file config is a FILE type upload
|
|
||||||
*/
|
|
||||||
export function isFileUpload(file: FileConfigResponse): boolean {
|
|
||||||
return file.type === "FILE" && !!file.file?.fileKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get fileKey from file config (only for FILE type)
|
* Get fileKey from file config (only for FILE type)
|
||||||
*/
|
*/
|
||||||
export function getFileKey(file: FileConfigResponse): string | undefined {
|
export function getFileKey(file: FileConfigResponse): string | undefined {
|
||||||
return file.type === "FILE" ? file.file?.fileKey : undefined;
|
return isFileResource(file) ? file.file?.fileKey : undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user