ui fix
This commit is contained in:
44
AGENTS.md
44
AGENTS.md
@@ -53,12 +53,21 @@ src/
|
|||||||
│ ├── main.tsx # React 入口
|
│ ├── main.tsx # React 入口
|
||||||
│ ├── App.tsx # 根组件
|
│ ├── App.tsx # 根组件
|
||||||
│ ├── components/ # React 组件
|
│ ├── components/ # React 组件
|
||||||
│ └── stores/ # Zustand Stores
|
│ ├── stores/ # Zustand Stores
|
||||||
|
│ └── locales/ # i18n 翻译文件
|
||||||
└── tests/ # 测试配置
|
└── tests/ # 测试配置
|
||||||
├── setup.ts # 测试环境设置
|
├── setup.ts # 测试环境设置
|
||||||
└── mocks/ # Mock 文件
|
└── mocks/ # Mock 文件
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 数据流
|
||||||
|
|
||||||
|
```
|
||||||
|
Renderer (React) → Preload API → IPC → Main Process → Storage/Kintone API
|
||||||
|
↓
|
||||||
|
Result<T> 返回
|
||||||
|
```
|
||||||
|
|
||||||
## 3. 路径别名
|
## 3. 路径别名
|
||||||
|
|
||||||
| 别名 | 路径 |
|
| 别名 | 路径 |
|
||||||
@@ -123,6 +132,7 @@ type Result<T> = { success: true; data: T } | { success: false; error: string };
|
|||||||
|
|
||||||
- IPC 调用使用 `invoke` 返回 `Result<T>`
|
- IPC 调用使用 `invoke` 返回 `Result<T>`
|
||||||
- Preload 通过 `contextBridge.exposeInMainWorld` 暴露 API
|
- Preload 通过 `contextBridge.exposeInMainWorld` 暴露 API
|
||||||
|
- 所有 IPC handlers 集中在 `src/main/ipc-handlers.ts`
|
||||||
|
|
||||||
## 6. UI 组件规范
|
## 6. UI 组件规范
|
||||||
|
|
||||||
@@ -138,20 +148,27 @@ export const useStyles = createStyles(({ token, css }) => ({
|
|||||||
}));
|
}));
|
||||||
```
|
```
|
||||||
|
|
||||||
- 国际化:使用日文默认 `import jaJP from 'antd/locale/ja_JP'`
|
|
||||||
- 禁止使用 Tailwind
|
- 禁止使用 Tailwind
|
||||||
|
- **ESM Only**: LobeHub UI 仅支持 ESM
|
||||||
|
|
||||||
## 7. 安全规范
|
## 7. 国际化 (i18n)
|
||||||
|
|
||||||
|
- 支持语言: `en-US`, `ja-JP`, `zh-CN`
|
||||||
|
- 翻译文件位置: `src/renderer/src/locales/{locale}/{namespace}.json`
|
||||||
|
- 使用 `react-i18next` 进行翻译
|
||||||
|
- Ant Design 默认使用日文: `import jaJP from 'antd/locale/ja_JP'`
|
||||||
|
|
||||||
|
## 8. 安全规范
|
||||||
|
|
||||||
- 密码使用 `electron` 的 `safeStorage` 加密存储
|
- 密码使用 `electron` 的 `safeStorage` 加密存储
|
||||||
- WebPreferences 必须:`contextIsolation: true`, `nodeIntegration: false`, `sandbox: false`
|
- WebPreferences 必须:`contextIsolation: true`, `nodeIntegration: false`, `sandbox: false`
|
||||||
|
|
||||||
## 8. 错误处理
|
## 9. 错误处理
|
||||||
|
|
||||||
- 所有 IPC 返回 `Result<T>` 格式
|
- 所有 IPC 返回 `Result<T>` 格式
|
||||||
- 渲染进程检查 `result.success` 处理错误
|
- 渲染进程检查 `result.success` 处理错误
|
||||||
|
|
||||||
## 9. fnm 环境配置
|
## 10. fnm 环境配置
|
||||||
|
|
||||||
所有 npm/npx 命令需加载 fnm 环境:
|
所有 npm/npx 命令需加载 fnm 环境:
|
||||||
|
|
||||||
@@ -163,20 +180,19 @@ export const useStyles = createStyles(({ token, css }) => ({
|
|||||||
eval "$(fnm env --use-on-cd)" && npm run dev
|
eval "$(fnm env --use-on-cd)" && npm run dev
|
||||||
```
|
```
|
||||||
|
|
||||||
## 10. 注意事项
|
## 11. 技术栈约束
|
||||||
|
|
||||||
1. **ESM Only**: LobeHub UI 仅支持 ESM
|
1. **React 19**: 使用 `@types/react@^19.0.0`
|
||||||
2. **React 19**: 使用 `@types/react@^19.0.0`
|
2. **CSS 方案**: 使用 `antd-style`,禁止 Tailwind
|
||||||
3. **CSS 方案**: 使用 `antd-style`,禁止 Tailwind
|
3. **禁止 `as any`**: 使用类型守卫或 `unknown`
|
||||||
4. **禁止 `as any`**: 使用类型守卫或 `unknown`
|
4. **函数组件优先**: 禁止 class 组件
|
||||||
5. **函数组件优先**: 禁止 class 组件
|
|
||||||
|
|
||||||
## 11. 沟通规范
|
## 12. 沟通规范
|
||||||
|
|
||||||
1. **人设**: 在回答的末尾加上「🦐」,用于确认上下文是否被正确保留
|
1. **人设**: 在回答的末尾加上「🦐」,用于确认上下文是否被正确保留
|
||||||
2. **语言**: 使用中文进行回答
|
2. **语言**: 使用中文进行回答
|
||||||
|
|
||||||
## 12. MVP Phase - Breaking Changes
|
## 13. MVP Phase - Breaking Changes
|
||||||
|
|
||||||
**This is MVP phase - breaking changes are acceptable for better design.** However, you MUST:
|
**This is MVP phase - breaking changes are acceptable for better design.** However, you MUST:
|
||||||
|
|
||||||
@@ -202,7 +218,7 @@ eval "$(fnm env --use-on-cd)" && npm run dev
|
|||||||
4. If significant, ask user for confirmation before implementing
|
4. If significant, ask user for confirmation before implementing
|
||||||
5. Update related documentation after implementation
|
5. Update related documentation after implementation
|
||||||
|
|
||||||
## 13. 测试规范
|
## 14. 测试规范
|
||||||
|
|
||||||
### 测试框架
|
### 测试框架
|
||||||
|
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ const { Header, Content, Sider } = Layout;
|
|||||||
const { Title } = Typography;
|
const { Title } = Typography;
|
||||||
|
|
||||||
// Domain section heights
|
// Domain section heights
|
||||||
const DOMAIN_SECTION_COLLAPSED = 76; // 增加高度,避免按钮覆盖文字
|
const DOMAIN_SECTION_COLLAPSED = 68; // 增加高度,避免按钮覆盖文字
|
||||||
const DOMAIN_SECTION_EXPANDED = 240;
|
const DOMAIN_SECTION_EXPANDED = 260;
|
||||||
const DEFAULT_SIDER_WIDTH = 320;
|
const DEFAULT_SIDER_WIDTH = 320;
|
||||||
const MIN_SIDER_WIDTH = 280;
|
const MIN_SIDER_WIDTH = 280;
|
||||||
const MAX_SIDER_WIDTH = 500;
|
const MAX_SIDER_WIDTH = 500;
|
||||||
@@ -61,13 +61,12 @@ const useStyles = createStyles(({ token, css }) => ({
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
`,
|
`,
|
||||||
logo: css`
|
logo: css`
|
||||||
height: 48px;
|
height: 32px;
|
||||||
margin: 8px 16px;
|
margin: ${token.paddingXS}px ${token.padding}px ${token.paddingXXS}px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
border-bottom: 1px solid ${token.colorBorderSecondary};
|
|
||||||
`,
|
`,
|
||||||
logoText: css`
|
logoText: css`
|
||||||
color: ${token.colorText};
|
color: ${token.colorText};
|
||||||
@@ -75,7 +74,7 @@ const useStyles = createStyles(({ token, css }) => ({
|
|||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
`,
|
`,
|
||||||
siderContent: css`
|
siderContent: css`
|
||||||
height: calc(100vh - 64px);
|
height: calc(100vh - 44px);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
`,
|
`,
|
||||||
@@ -113,6 +112,7 @@ const useStyles = createStyles(({ token, css }) => ({
|
|||||||
`,
|
`,
|
||||||
domainSection: css`
|
domainSection: css`
|
||||||
border-bottom: 1px solid ${token.colorBorderSecondary};
|
border-bottom: 1px solid ${token.colorBorderSecondary};
|
||||||
|
padding-bottom: ${token.paddingXS}px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
transition: height 0.2s ease-in-out;
|
transition: height 0.2s ease-in-out;
|
||||||
`,
|
`,
|
||||||
@@ -216,7 +216,7 @@ const App: React.FC = () => {
|
|||||||
style={{ display: "flex", alignItems: "center", gap: 8 }}
|
style={{ display: "flex", alignItems: "center", gap: 8 }}
|
||||||
>
|
>
|
||||||
<Cloud size={24} style={{ color: token.colorPrimary }} />
|
<Cloud size={24} style={{ color: token.colorPrimary }} />
|
||||||
<span className={styles.logoText}>Kintone Manager</span>
|
<span className={styles.logoText}>Kintone JS/CSS Manager</span>
|
||||||
</div>
|
</div>
|
||||||
<Tooltip title={t("collapseSidebar")} mouseEnterDelay={0.5}>
|
<Tooltip title={t("collapseSidebar")} mouseEnterDelay={0.5}>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ const useStyles = createStyles(({ token, css }) => ({
|
|||||||
|
|
||||||
actions: css`
|
actions: css`
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: ${token.paddingXS}px;
|
right: ${token.paddingXXS}px;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -7,15 +7,19 @@
|
|||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Spin } from "antd";
|
import { Spin } from "antd";
|
||||||
import { Button, Tooltip, Avatar, Empty } from "@lobehub/ui";
|
import { Button, Tooltip, Avatar, Empty, Block } from "@lobehub/ui";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Plus, Cloud, ChevronUp, ChevronDown } from "lucide-react";
|
import { Plus, Building, ChevronUp, ChevronDown } from "lucide-react";
|
||||||
import { createStyles } from "antd-style";
|
import { createStyles } from "antd-style";
|
||||||
import { useDomainStore, useUIStore } from "@renderer/stores";
|
import { useDomainStore } from "@renderer/stores";
|
||||||
import DomainList from "./DomainList";
|
import DomainList from "./DomainList";
|
||||||
import DomainForm from "./DomainForm";
|
import DomainForm from "./DomainForm";
|
||||||
|
|
||||||
const useStyles = createStyles(({ token, css }) => ({
|
const useStyles = createStyles(({ token, css }) => ({
|
||||||
|
wrapper: css`
|
||||||
|
height: 100%;
|
||||||
|
margin: 0 ${token.paddingSM}px;
|
||||||
|
`,
|
||||||
container: css`
|
container: css`
|
||||||
height: 100%;
|
height: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -24,37 +28,34 @@ const useStyles = createStyles(({ token, css }) => ({
|
|||||||
border-radius: ${token.borderRadiusLG}px;
|
border-radius: ${token.borderRadiusLG}px;
|
||||||
padding: ${token.paddingSM}px;
|
padding: ${token.paddingSM}px;
|
||||||
`,
|
`,
|
||||||
collapsedContainer: css`
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
background: ${token.colorFillSecondary};
|
|
||||||
border-radius: ${token.borderRadiusLG}px;
|
|
||||||
padding: ${token.paddingSM}px;
|
|
||||||
position: relative;
|
|
||||||
`,
|
|
||||||
header: css`
|
header: css`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: ${token.paddingXXS}px ${token.paddingSM}px;
|
||||||
|
`,
|
||||||
|
headerLeft: css`
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: ${token.marginXXS}px;
|
flex: 1;
|
||||||
padding: 0 ${token.paddingLG}px;
|
cursor: pointer;
|
||||||
padding-top: ${token.paddingXS}px;
|
padding-right: ${token.paddingSM}px;
|
||||||
|
`,
|
||||||
|
headerRight: css`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: ${token.paddingXS}px;
|
||||||
`,
|
`,
|
||||||
title: css`
|
title: css`
|
||||||
font-size: ${token.fontSizeHeading4}px;
|
font-size: ${token.fontSize}px;
|
||||||
font-weight: ${token.fontWeightStrong};
|
font-weight: ${token.fontWeightStrong};
|
||||||
color: ${token.colorText};
|
color: ${token.colorText};
|
||||||
margin: 0;
|
margin: 0;
|
||||||
`,
|
`,
|
||||||
actions: css`
|
|
||||||
display: flex;
|
|
||||||
gap: ${token.paddingXS}px;
|
|
||||||
`,
|
|
||||||
content: css`
|
content: css`
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding: 0 ${token.paddingSM}px;
|
padding: 0 ${token.paddingXXS}px;
|
||||||
`,
|
`,
|
||||||
loading: css`
|
loading: css`
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -62,21 +63,6 @@ const useStyles = createStyles(({ token, css }) => ({
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
height: 200px;
|
height: 200px;
|
||||||
`,
|
`,
|
||||||
collapsedHeader: css`
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
padding: ${token.paddingSM}px ${token.paddingMD}px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background 0.2s;
|
|
||||||
`,
|
|
||||||
collapsedInfo: css`
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: ${token.paddingSM}px;
|
|
||||||
flex: 1;
|
|
||||||
min-width: 0;
|
|
||||||
`,
|
|
||||||
collapsedName: css`
|
collapsedName: css`
|
||||||
font-weight: ${token.fontWeightStrong};
|
font-weight: ${token.fontWeightStrong};
|
||||||
font-size: ${token.fontSize}px;
|
font-size: ${token.fontSize}px;
|
||||||
@@ -84,21 +70,38 @@ const useStyles = createStyles(({ token, css }) => ({
|
|||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
`,
|
`,
|
||||||
collapsedUrl: css`
|
collapsedDesc: css`
|
||||||
color: ${token.colorTextSecondary};
|
color: ${token.colorTextSecondary};
|
||||||
font-size: ${token.fontSizeSM}px;
|
font-size: ${token.fontSizeSM}px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
`,
|
`,
|
||||||
collapsedActions: css`
|
|
||||||
display: flex;
|
|
||||||
gap: ${token.paddingXS}px;
|
|
||||||
`,
|
|
||||||
noDomainText: css`
|
noDomainText: css`
|
||||||
color: ${token.colorTextSecondary};
|
color: ${token.colorTextSecondary};
|
||||||
font-size: ${token.fontSizeSM}px;
|
font-size: ${token.fontSizeSM}px;
|
||||||
padding: ${token.paddingSM}px ${token.paddingMD}px;
|
`,
|
||||||
|
collapsedBlock: css`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: 8px;
|
||||||
|
`,
|
||||||
|
collapsedInfo: css`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
`,
|
||||||
|
collapsedText: css`
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
`,
|
||||||
|
collapsedIcon: css`
|
||||||
|
flex-shrink: 0;
|
||||||
`,
|
`,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -114,7 +117,6 @@ const DomainManager: React.FC<DomainManagerProps> = ({
|
|||||||
const { t } = useTranslation("domain");
|
const { t } = useTranslation("domain");
|
||||||
const { styles } = useStyles();
|
const { styles } = useStyles();
|
||||||
const { domains, loading, loadDomains, currentDomain } = useDomainStore();
|
const { domains, loading, loadDomains, currentDomain } = useDomainStore();
|
||||||
const { domainIconColors } = useUIStore();
|
|
||||||
const [formOpen, setFormOpen] = React.useState(false);
|
const [formOpen, setFormOpen] = React.useState(false);
|
||||||
const [editingDomain, setEditingDomain] = React.useState<string | null>(null);
|
const [editingDomain, setEditingDomain] = React.useState<string | null>(null);
|
||||||
|
|
||||||
@@ -137,65 +139,53 @@ const DomainManager: React.FC<DomainManagerProps> = ({
|
|||||||
setEditingDomain(null);
|
setEditingDomain(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getDomainIconColor = (domainId: string | undefined) => {
|
|
||||||
if (!domainId) return "#d9d9d9";
|
|
||||||
return domainIconColors[domainId] || "#1890ff";
|
|
||||||
};
|
|
||||||
|
|
||||||
// Collapsed view - show current domain only
|
// Collapsed view - show current domain only
|
||||||
if (collapsed) {
|
if (collapsed) {
|
||||||
return (
|
return (
|
||||||
<div className={styles.collapsedContainer}>
|
<>
|
||||||
<div className={styles.collapsedHeader} onClick={onToggleCollapse}>
|
<div className={styles.wrapper}>
|
||||||
<div className={styles.collapsedInfo}>
|
<Block
|
||||||
<Avatar
|
direction="horizontal"
|
||||||
icon={<Cloud size={14} />}
|
variant="filled"
|
||||||
size={24}
|
clickable
|
||||||
style={{
|
onClick={onToggleCollapse}
|
||||||
backgroundColor: getDomainIconColor(currentDomain?.id),
|
className={styles.collapsedBlock}
|
||||||
}}
|
>
|
||||||
/>
|
<div className={styles.collapsedInfo}>
|
||||||
<div style={{ flex: 1, minWidth: 0 }}>
|
<Avatar
|
||||||
{currentDomain ? (
|
size={36}
|
||||||
<>
|
className={styles.collapsedIcon}
|
||||||
<div className={styles.collapsedName}>
|
icon={<Building size={18} />}
|
||||||
{currentDomain.name}
|
/>
|
||||||
|
<div className={styles.collapsedText}>
|
||||||
|
{currentDomain ? (
|
||||||
|
<>
|
||||||
|
<div className={styles.collapsedName}>
|
||||||
|
{currentDomain.name}
|
||||||
|
</div>
|
||||||
|
<div className={styles.collapsedDesc}>
|
||||||
|
{currentDomain.username} · <a target="_blank" href={"https://" + currentDomain.domain}>{currentDomain.domain}</a>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div className={styles.noDomainText}>
|
||||||
|
{t("noDomainSelected")}
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.collapsedUrl}>
|
)}
|
||||||
{currentDomain.username} · {currentDomain.domain}
|
</div>
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<div className={styles.collapsedName}>
|
|
||||||
{t("noDomainSelected")}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div className={styles.collapsedActions}>
|
|
||||||
<Tooltip title={t("expand")}>
|
<Tooltip title={t("expand")}>
|
||||||
<Button
|
<Button
|
||||||
type="text"
|
type="text"
|
||||||
size="small"
|
size="small"
|
||||||
icon={<ChevronDown size={16} />}
|
icon={<ChevronDown size={18} />}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
onToggleCollapse?.();
|
onToggleCollapse?.();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title={t("addDomain")}>
|
</Block>
|
||||||
<Button
|
|
||||||
type="text"
|
|
||||||
size="small"
|
|
||||||
icon={<Plus size={16} />}
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation();
|
|
||||||
handleAdd();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<DomainForm
|
<DomainForm
|
||||||
@@ -203,50 +193,53 @@ const DomainManager: React.FC<DomainManagerProps> = ({
|
|||||||
onClose={handleCloseForm}
|
onClose={handleCloseForm}
|
||||||
domainId={editingDomain}
|
domainId={editingDomain}
|
||||||
/>
|
/>
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expanded view - full list
|
// Expanded view - full list
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<>
|
||||||
<div className={styles.header}>
|
<div className={styles.wrapper}>
|
||||||
<h2 className={styles.title}>{t("domainManagement")}</h2>
|
<div className={styles.container}>
|
||||||
<div className={styles.actions}>
|
<div className={styles.header}>
|
||||||
<Tooltip title={t("collapse")}>
|
<Tooltip title={t("collapse")} placement="topRight">
|
||||||
<Button
|
<div className={styles.headerLeft} onClick={onToggleCollapse}>
|
||||||
type="text"
|
<h3 className={styles.title}>{t("domainManagement")}</h3>
|
||||||
size="small"
|
<ChevronUp size={16} style={{ opacity: 0.5 }} />
|
||||||
icon={<ChevronUp size={16} />}
|
</div>
|
||||||
onClick={onToggleCollapse}
|
</Tooltip>
|
||||||
/>
|
<div className={styles.headerRight}>
|
||||||
</Tooltip>
|
<Tooltip title={t("addDomain")}>
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
icon={<Plus size={16} />}
|
size="small"
|
||||||
onClick={handleAdd}
|
icon={<Plus size={16} />}
|
||||||
></Button>
|
onClick={handleAdd}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.content}>
|
||||||
|
{loading && domains.length === 0 ? (
|
||||||
|
<div className={styles.loading}>
|
||||||
|
<Spin size="large" />
|
||||||
|
</div>
|
||||||
|
) : domains.length === 0 ? (
|
||||||
|
<Empty description={t("noDomainConfig")}></Empty>
|
||||||
|
) : (
|
||||||
|
<DomainList onEdit={handleEdit} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.content}>
|
|
||||||
{loading && domains.length === 0 ? (
|
|
||||||
<div className={styles.loading}>
|
|
||||||
<Spin size="large" />
|
|
||||||
</div>
|
|
||||||
) : domains.length === 0 ? (
|
|
||||||
<Empty description={t("noDomainConfig")}></Empty>
|
|
||||||
) : (
|
|
||||||
<DomainList onEdit={handleEdit} />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<DomainForm
|
<DomainForm
|
||||||
open={formOpen}
|
open={formOpen}
|
||||||
onClose={handleCloseForm}
|
onClose={handleCloseForm}
|
||||||
domainId={editingDomain}
|
domainId={editingDomain}
|
||||||
/>
|
/>
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"appName": "Kintone Manager",
|
"appName": "Kintone JS/CSS Manager",
|
||||||
"save": "Save",
|
"save": "Save",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"delete": "Delete",
|
"delete": "Delete",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"appName": "Kintone Manager",
|
"appName": "Kintone JS/CSS Manager",
|
||||||
"save": "保存",
|
"save": "保存",
|
||||||
"cancel": "キャンセル",
|
"cancel": "キャンセル",
|
||||||
"delete": "削除",
|
"delete": "削除",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"appName": "Kintone Manager",
|
"appName": "Kintone JS/CSS Manager",
|
||||||
"save": "保存",
|
"save": "保存",
|
||||||
"cancel": "取消",
|
"cancel": "取消",
|
||||||
"delete": "删除",
|
"delete": "删除",
|
||||||
|
|||||||
Reference in New Issue
Block a user