remove wrong deploy btn

This commit is contained in:
2026-03-17 22:16:13 +08:00
parent 23a4e1e8cb
commit 0f9f1a94fa
12 changed files with 106 additions and 760 deletions

View File

@@ -5,18 +5,12 @@
import React from "react";
import { useTranslation } from "react-i18next";
import {
Layout,
Typography,
Space,
Modal,
} from "antd";
import { Layout, Typography, Space, Modal } from "antd";
import { Button, Tooltip } from "@lobehub/ui";
import {
Cloud,
CloudUpload,
History,
PanelLeftClose,
PanelLeftOpen,
@@ -29,7 +23,6 @@ import { useUIStore } from "@renderer/stores";
import { DomainManager } from "@renderer/components/DomainManager";
import { AppList } from "@renderer/components/AppList";
import { AppDetail } from "@renderer/components/AppDetail";
import { DeployDialog } from "@renderer/components/DeployDialog";
import { Settings } from "@renderer/components/Settings";
const { Header, Content, Sider } = Layout;
const { Title } = Typography;
@@ -173,7 +166,6 @@ const App: React.FC = () => {
setSiderCollapsed,
setDomainExpanded,
} = useUIStore();
const [deployDialogOpen, setDeployDialogOpen] = React.useState(false);
const [settingsOpen, setSettingsOpen] = React.useState(false);
const [isResizing, setIsResizing] = React.useState(false);
@@ -226,9 +218,7 @@ const App: React.FC = () => {
{!siderCollapsed && (
<>
<div className={styles.logo}>
<div
style={{ display: "flex", alignItems: "center", gap: 8 }}
>
<div style={{ display: "flex", alignItems: "center", gap: 8 }}>
<Cloud size={24} style={{ color: token.colorPrimary }} />
<span className={styles.logoText}>Kintone JS/CSS Manager</span>
</div>
@@ -249,9 +239,7 @@ const App: React.FC = () => {
>
<DomainManager
collapsed={!domainExpanded}
onToggleCollapse={() =>
setDomainExpanded(!domainExpanded)
}
onToggleCollapse={() => setDomainExpanded(!domainExpanded)}
/>
</div>
<div
@@ -265,7 +253,9 @@ const App: React.FC = () => {
<div
className={styles.resizeHandle}
onMouseDown={handleResizeStart}
style={{ background: isResizing ? token.colorPrimary : undefined }}
style={{
background: isResizing ? token.colorPrimary : undefined,
}}
/>
</>
)}
@@ -289,20 +279,10 @@ const App: React.FC = () => {
</Tooltip>
)}
<Title level={5} style={{ margin: 0 }}>
{currentDomain
? currentDomain.name
: "Kintone Customize Manager"}
{currentDomain ? currentDomain.name : "Kintone Customize Manager"}
</Title>
</div>
<Space>
<Button
type="primary"
icon={<CloudUpload size={16} />}
onClick={() => setDeployDialogOpen(true)}
disabled={!currentDomain}
>
{t("deployFiles")}
</Button>
<Button icon={<History size={16} />} disabled={!currentDomain}>
{t("versionHistory")}
</Button>
@@ -312,7 +292,6 @@ const App: React.FC = () => {
onClick={() => setSettingsOpen(true)}
/>
</Tooltip>
</Space>
</Header>
@@ -325,12 +304,6 @@ const App: React.FC = () => {
</Content>
</Layout>
{/* Deploy Dialog */}
<DeployDialog
open={deployDialogOpen}
onClose={() => setDeployDialogOpen(false)}
/>
{/* Settings Modal */}
<Modal
title={t("settings")}
@@ -342,7 +315,6 @@ const App: React.FC = () => {
>
<Settings />
</Modal>
</Layout>
);
};

View File

@@ -1,426 +0,0 @@
/**
* DeployDialog Component
* Dialog for confirming and executing deployment
*/
import React from "react";
import { useTranslation } from "react-i18next";
import {
Steps,
Space,
Alert,
Spin,
Result,
Table,
Tag,
Typography,
Divider,
} from "antd";
import { Button, Modal, Select } from "@lobehub/ui";
import {
CloudUpload,
CheckCircle,
XCircle,
Loader2,
} from "lucide-react";
import { createStyles } from "antd-style";
import { FileUploader } from "../FileUploader";
import { useDeployStore } from "@renderer/stores";
import { useDomainStore } from "@renderer/stores";
import { useAppStore } from "@renderer/stores";
import type { DeployFile } from "@shared/types/ipc";
const { Text } = Typography;
const useStyles = createStyles(({ token, css }) => ({
container: css`
min-height: 400px;
`,
stepContent: css`
margin-top: ${token.marginMD}px;
`,
positionSelector: css`
margin-bottom: ${token.marginMD}px;
`,
positionItem: css`
display: flex;
align-items: center;
justify-content: space-between;
padding: ${token.paddingSM}px ${token.paddingMD}px;
border: 1px solid ${token.colorBorderSecondary};
border-radius: ${token.borderRadiusLG}px;
margin-bottom: ${token.marginSM}px;
`,
summary: css`
padding: ${token.paddingMD}px;
background: ${token.colorBgLayout};
border-radius: ${token.borderRadiusLG}px;
`,
summaryItem: css`
display: flex;
justify-content: space-between;
padding: ${token.paddingXS}px 0;
`,
}));
interface DeployDialogProps {
open: boolean;
onClose: () => void;
onSuccess?: () => void;
}
const DeployDialog: React.FC<DeployDialogProps> = ({
open,
onClose,
onSuccess,
}) => {
const { t } = useTranslation("deploy");
const { styles } = useStyles();
const { currentDomain } = useDomainStore();
const { currentApp } = useAppStore();
const {
step,
files,
setStep,
setFiles,
setTargetAppId,
setDeploying,
setResult,
setError,
reset,
} = useDeployStore();
// Reset when dialog opens
React.useEffect(() => {
if (open) {
reset();
if (currentApp) {
setTargetAppId(currentApp.appId);
}
}
}, [open]);
const handleDeploy = async () => {
if (!currentDomain || !currentApp) return;
setStep("deploying");
setDeploying(true);
try {
const result = await window.api.deploy({
domainId: currentDomain.id,
appId: currentApp.appId,
files,
});
if (result.success) {
setResult(result);
setStep("success");
onSuccess?.();
} else {
setError(result.error || t("deployFailed"));
setStep("error");
}
} catch (error) {
setError(error instanceof Error ? error.message : t("deployFailed"));
setStep("error");
} finally {
setDeploying(false);
}
};
const handleClose = () => {
reset();
onClose();
};
const handleFilesChange = (newFiles: DeployFile[]) => {
setFiles(newFiles);
};
const handlePositionChange = (
index: number,
position: DeployFile["position"],
) => {
const newFiles = [...files];
newFiles[index] = { ...newFiles[index], position };
setFiles(newFiles);
};
const canProceedToConfigure = files.length > 0;
const canProceedToConfirm = files.every((f) => f.position);
// Position options for JS files
const jsPositionOptions = [
{ value: "pc_header", label: t("pcHeader") },
{ value: "pc_body", label: t("pcBody") },
{ value: "pc_footer", label: t("pcFooter") },
{ value: "mobile_header", label: t("mobileHeader") },
{ value: "mobile_body", label: t("mobileBody") },
{ value: "mobile_footer", label: t("mobileFooter") },
];
// Position options for CSS files
const cssPositionOptions = [
{ value: "pc_css", label: t("pc") },
{ value: "mobile_css", label: t("mobile") },
];
const renderStepContent = () => {
switch (step) {
case "select":
return (
<div className={styles.stepContent}>
<Alert
message={t("selectFiles")}
description={t("selectFilesDesc")}
type="info"
showIcon
style={{ marginBottom: 16 }}
/>
<FileUploader files={files} onChange={handleFilesChange} />
</div>
);
case "configure":
return (
<div className={styles.stepContent}>
<Alert
message={t("configurePosition")}
description={t("configurePositionDesc")}
type="info"
showIcon
style={{ marginBottom: 16 }}
/>
{files.map((file, index) => (
<div key={index} className={styles.positionItem}>
<Space>
<Tag color={file.fileType === "js" ? "gold" : "blue"}>
{file.fileType.toUpperCase()}
</Tag>
<Text>{file.fileName}</Text>
</Space>
<Select
value={file.position}
onChange={(value) => handlePositionChange(index, value)}
options={
file.fileType === "js"
? jsPositionOptions
: cssPositionOptions
}
style={{ width: 200 }}
/>
</div>
))}
</div>
);
case "confirm":
return (
<div className={styles.stepContent}>
<Alert
message={t("confirmDeployment")}
description={t("confirmDeploymentDesc")}
type="warning"
showIcon
style={{ marginBottom: 16 }}
/>
<div className={styles.summary}>
<div className={styles.summaryItem}>
<Text strong>{t("targetDomain")}</Text>
<Text>{currentDomain?.name}</Text>
</div>
<div className={styles.summaryItem}>
<Text strong>{t("targetApp")}</Text>
<Text>
{currentApp?.name} ({currentApp?.appId})
</Text>
</div>
<Divider style={{ margin: "12px 0" }} />
<Text strong>{t("deployFiles")}</Text>
<Table
size="small"
dataSource={files.map((f, i) => ({ ...f, key: i }))}
columns={[
{
title: t("fileName"),
dataIndex: "fileName",
key: "fileName",
},
{
title: t("type"),
dataIndex: "fileType",
key: "fileType",
render: (type) => (
<Tag color={type === "js" ? "gold" : "blue"}>
{type.toUpperCase()}
</Tag>
),
},
{
title: t("position"),
dataIndex: "position",
key: "position",
render: (pos) => {
const labels: Record<string, string> = {
pc_header: t("pcHeader"),
pc_body: t("pcBody"),
pc_footer: t("pcFooter"),
mobile_header: t("mobileHeader"),
mobile_body: t("mobileBody"),
mobile_footer: t("mobileFooter"),
pc_css: t("pc"),
mobile_css: t("mobile"),
};
return labels[pos] || pos;
},
},
]}
pagination={false}
/>
</div>
</div>
);
case "deploying":
return (
<div
className={styles.stepContent}
style={{ textAlign: "center", padding: 48 }}
>
<Spin
indicator={<Loader2 size={48} className="animate-spin" />}
/>
<div style={{ marginTop: 24 }}>
<Text>{t("deploying")}</Text>
</div>
</div>
);
case "success":
return (
<div className={styles.stepContent}>
<Result
status="success"
title={t("deploySuccess")}
subTitle={t("deploySuccessDesc")}
extra={[
<Button type="primary" key="close" onClick={handleClose}>
{t("done")}
</Button>,
]}
/>
</div>
);
case "error":
return (
<div className={styles.stepContent}>
<Result
status="error"
title={t("deployFailed")}
subTitle={t("deployFailedDesc")}
extra={[
<Button key="retry" onClick={() => setStep("confirm")}>
{t("retry")}
</Button>,
<Button key="close" onClick={handleClose}>
{t("close", { ns: "common" })}
</Button>,
]}
/>
</div>
);
default:
return null;
}
};
const currentStepIndex = [
"select",
"configure",
"confirm",
"deploying",
"success",
"error",
].indexOf(step);
return (
<Modal
title={
<Space>
<CloudUpload size={16} />
{t("title")}
</Space>
}
open={open}
onCancel={step === "deploying" ? undefined : handleClose}
width={640}
footer={
step === "deploying" ||
step === "success" ||
step === "error" ? null : (
<Space>
<Button onClick={handleClose}>
{t("cancel", { ns: "common" })}
</Button>
{step === "select" && (
<Button
type="primary"
disabled={!canProceedToConfigure}
onClick={() => setStep("configure")}
>
{t("next", { ns: "common" })}
</Button>
)}
{step === "configure" && (
<>
<Button onClick={() => setStep("select")}>
{t("back", { ns: "common" })}
</Button>
<Button
type="primary"
disabled={!canProceedToConfirm}
onClick={() => setStep("confirm")}
>
{t("next", { ns: "common" })}
</Button>
</>
)}
{step === "confirm" && (
<>
<Button onClick={() => setStep("configure")}>
{t("back", { ns: "common" })}
</Button>
<Button type="primary" onClick={handleDeploy}>
{t("confirmDeploy")}
</Button>
</>
)}
</Space>
)
}
destroyOnHidden
mask={{ closable: false }}
>
<div className={styles.container}>
{step !== "success" && step !== "error" && step !== "deploying" && (
<Steps
size="small"
current={currentStepIndex}
items={[
{ title: t("selectFile") },
{ title: t("configurePos") },
{ title: t("confirmDeployment") },
]}
/>
)}
{renderStepContent()}
</div>
</Modal>
);
};
export default DeployDialog;

View File

@@ -1,6 +0,0 @@
/**
* DeployDialog Components
* Export all deploy dialog components
*/
export { default as DeployDialog } from "./DeployDialog";

View File

@@ -8,7 +8,6 @@ import domainZHCN from "./locales/zh-CN/domain.json";
import settingsZHCN from "./locales/zh-CN/settings.json";
import errorsZHCN from "./locales/zh-CN/errors.json";
import appZHCN from "./locales/zh-CN/app.json";
import deployZHCN from "./locales/zh-CN/deploy.json";
import fileZHCN from "./locales/zh-CN/file.json";
import versionZHCN from "./locales/zh-CN/version.json";
import commonJAJP from "./locales/ja-JP/common.json";
@@ -16,7 +15,6 @@ import domainJAJP from "./locales/ja-JP/domain.json";
import settingsJAJP from "./locales/ja-JP/settings.json";
import errorsJAJP from "./locales/ja-JP/errors.json";
import appJAJP from "./locales/ja-JP/app.json";
import deployJAJP from "./locales/ja-JP/deploy.json";
import fileJAJP from "./locales/ja-JP/file.json";
import versionJAJP from "./locales/ja-JP/version.json";
import commonENUS from "./locales/en-US/common.json";
@@ -24,7 +22,6 @@ import domainENUS from "./locales/en-US/domain.json";
import settingsENUS from "./locales/en-US/settings.json";
import errorsENUS from "./locales/en-US/errors.json";
import appENUS from "./locales/en-US/app.json";
import deployENUS from "./locales/en-US/deploy.json";
import fileENUS from "./locales/en-US/file.json";
import versionENUS from "./locales/en-US/version.json";
// Define resources with namespaces
@@ -35,7 +32,6 @@ const resources = {
settings: settingsZHCN,
errors: errorsZHCN,
app: appZHCN,
deploy: deployZHCN,
file: fileZHCN,
version: versionZHCN,
},
@@ -45,7 +41,6 @@ const resources = {
settings: settingsJAJP,
errors: errorsJAJP,
app: appJAJP,
deploy: deployJAJP,
file: fileJAJP,
version: versionJAJP,
},
@@ -55,7 +50,6 @@ const resources = {
settings: settingsENUS,
errors: errorsENUS,
app: appENUS,
deploy: deployENUS,
file: fileENUS,
version: versionENUS,
},
@@ -68,7 +62,7 @@ i18next
.init({
resources,
fallbackLng: "ja-JP",
ns: ["common", "domain", "settings", "errors", "app", "deploy", "file", "version"],
ns: ["common", "domain", "settings", "errors", "app", "file", "version"],
interpolation: {
escapeValue: false, // React already handles escaping
},

View File

@@ -30,7 +30,6 @@
"paste": "Paste",
"cut": "Cut",
"selectAll": "Select all",
"deployFiles": "Deploy Files",
"versionHistory": "Version History",
"settings": "Settings",
"downloadSuccess": "Download successful",

View File

@@ -1,33 +0,0 @@
{
"title": "Deploy Files",
"selectFiles": "Select files to deploy",
"selectFilesDesc": "Drag and drop or select JavaScript or CSS files to deploy",
"configurePosition": "Configure deployment position",
"configurePositionDesc": "Select deployment position for each file",
"confirmDeployment": "Confirm deployment",
"confirmDeploymentDesc": "Please confirm the following deployment information",
"targetDomain": "Target Domain",
"targetApp": "Target App",
"deployFiles": "Files to deploy:",
"fileName": "File Name",
"type": "Type",
"position": "Position",
"deploying": "Deploying to Kintone...",
"deploySuccess": "Deployment Successful",
"deploySuccessDesc": "Files have been successfully deployed to Kintone",
"deployFailed": "Deployment Failed",
"deployFailedDesc": "An error occurred during deployment",
"done": "Done",
"retry": "Retry",
"confirmDeploy": "Confirm Deploy",
"selectFile": "Select Files",
"configurePos": "Configure Position",
"pcHeader": "PC - Header",
"pcBody": "PC - Body",
"pcFooter": "PC - Footer",
"mobileHeader": "Mobile - Header",
"mobileBody": "Mobile - Body",
"mobileFooter": "Mobile - Footer",
"pc": "PC",
"mobile": "Mobile"
}

View File

@@ -30,7 +30,6 @@
"paste": "貼り付け",
"cut": "切り取り",
"selectAll": "すべて選択",
"deployFiles": "ファイルをデプロイ",
"versionHistory": "バージョン履歴",
"settings": "設定",
"downloadSuccess": "ダウンロード成功",

View File

@@ -1,33 +0,0 @@
{
"title": "ファイルをデプロイ",
"selectFiles": "デプロイするファイルを選択",
"selectFilesDesc": "デプロイするJavaScriptまたはCSSファイルをドラッグドロップまたは選択してください",
"configurePosition": "デプロイ位置を設定",
"configurePositionDesc": "各ファイルのデプロイ位置を選択してください",
"confirmDeployment": "デプロイ確認",
"confirmDeploymentDesc": "以下のデプロイ情報を確認してください",
"targetDomain": "ターゲットドメイン",
"targetApp": "ターゲットアプリ",
"deployFiles": "デプロイファイル:",
"fileName": "ファイル名",
"type": "タイプ",
"position": "位置",
"deploying": "Kintoneにデプロイ中...",
"deploySuccess": "デプロイ成功",
"deploySuccessDesc": "ファイルがKintoneに正常にデプロイされました",
"deployFailed": "デプロイ失敗",
"deployFailedDesc": "デプロイ中にエラーが発生しました",
"done": "完了",
"retry": "再試行",
"confirmDeploy": "デプロイ確認",
"selectFile": "ファイル選択",
"configurePos": "位置設定",
"pcHeader": "PC - ヘッダー",
"pcBody": "PC - ボディ",
"pcFooter": "PC - フッター",
"mobileHeader": "モバイル - ヘッダー",
"mobileBody": "モバイル - ボディ",
"mobileFooter": "モバイル - フッター",
"pc": "PC",
"mobile": "モバイル"
}

View File

@@ -30,7 +30,6 @@
"paste": "粘贴",
"cut": "剪切",
"selectAll": "全选",
"deployFiles": "部署文件",
"versionHistory": "版本历史",
"settings": "设置",
"downloadSuccess": "下载成功",

View File

@@ -1,33 +0,0 @@
{
"title": "部署文件",
"selectFiles": "选择要部署的文件",
"selectFilesDesc": "请拖拽或选择要部署的 JavaScript 或 CSS 文件",
"configurePosition": "配置部署位置",
"configurePositionDesc": "为每个文件选择部署位置",
"confirmDeployment": "确认部署",
"confirmDeploymentDesc": "请确认以下部署信息",
"targetDomain": "目标Domain",
"targetApp": "目标应用",
"deployFiles": "部署文件:",
"fileName": "文件名",
"type": "类型",
"position": "部署位置",
"deploying": "正在部署到 Kintone...",
"deploySuccess": "部署成功",
"deploySuccessDesc": "文件已成功部署到 Kintone",
"deployFailed": "部署失败",
"deployFailedDesc": "部署过程中发生错误",
"done": "完成",
"retry": "重试",
"confirmDeploy": "确认部署",
"selectFile": "选择文件",
"configurePos": "配置位置",
"pcHeader": "PC端 - Header",
"pcBody": "PC端 - Body",
"pcFooter": "PC端 - Footer",
"mobileHeader": "移动端 - Header",
"mobileBody": "移动端 - Body",
"mobileFooter": "移动端 - Footer",
"pc": "PC端",
"mobile": "移动端"
}

View File

@@ -1,85 +0,0 @@
/**
* Deploy Store
* Manages deployment state and parameters
*/
import { create } from "zustand";
import type { DeployFile, DeployResult } from "@shared/types/ipc";
export type DeployStep =
| "select"
| "configure"
| "confirm"
| "deploying"
| "success"
| "error";
interface DeployState {
// State
step: DeployStep;
files: DeployFile[];
targetAppId: string | null;
deploying: boolean;
result: DeployResult | null;
error: string | null;
// Actions
setStep: (step: DeployStep) => void;
setFiles: (files: DeployFile[]) => void;
addFile: (file: DeployFile) => void;
removeFile: (index: number) => void;
updateFile: (index: number, file: Partial<DeployFile>) => void;
setTargetAppId: (appId: string | null) => void;
setDeploying: (deploying: boolean) => void;
setResult: (result: DeployResult | null) => void;
setError: (error: string | null) => void;
clear: () => void;
reset: () => void;
}
const initialState = {
step: "select" as DeployStep,
files: [],
targetAppId: null,
deploying: false,
result: null,
error: null,
};
export const useDeployStore = create<DeployState>()((set) => ({
...initialState,
// Actions
setStep: (step) => set({ step }),
setFiles: (files) => set({ files }),
addFile: (file) =>
set((state) => ({
files: [...state.files, file],
})),
removeFile: (index) =>
set((state) => ({
files: state.files.filter((_, i) => i !== index),
})),
updateFile: (index, updates) =>
set((state) => ({
files: state.files.map((file, i) =>
i === index ? { ...file, ...updates } : file,
),
})),
setTargetAppId: (appId) => set({ targetAppId: appId }),
setDeploying: (deploying) => set({ deploying }),
setResult: (result) => set({ result }),
setError: (error) => set({ error }),
clear: () => set(initialState),
reset: () => set(initialState),
}));

View File

@@ -5,7 +5,6 @@
export { useDomainStore } from "./domainStore";
export { useAppStore } from "./appStore";
export { useDeployStore } from "./deployStore";
export { useVersionStore } from "./versionStore";
export { useUIStore } from "./uiStore";
export { useSessionStore } from "./sessionStore";