chore: remove .sisyphus task artifacts
This commit is contained in:
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"active_plan": "C:\\dev\\workspace\\kintone\\kintone-customize-manager\\.sisyphus\\plans\\i18n-integration.md",
|
|
||||||
"started_at": "2026-03-13T15:49:52.804Z",
|
|
||||||
"session_ids": [
|
|
||||||
"ses_3181c303bffeybo48ZtQ4KkVD8"
|
|
||||||
],
|
|
||||||
"plan_name": "i18n-integration",
|
|
||||||
"agent": "atlas"
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
# i18n Dependencies Installation Evidence
|
|
||||||
|
|
||||||
Date: 2026-03-13
|
|
||||||
|
|
||||||
## Installed Packages
|
|
||||||
|
|
||||||
```
|
|
||||||
+-- @lobehub/i18n-cli@1.26.1
|
|
||||||
+-- i18next-browser-languagedetector@8.2.1
|
|
||||||
+-- i18next@25.8.18
|
|
||||||
`-- react-i18next@16.5.8
|
|
||||||
`-- i18next@25.8.18 deduped
|
|
||||||
```
|
|
||||||
|
|
||||||
## Verification Command
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm ls i18next react-i18next i18next-browser-languagedetector @lobehub/i18n-cli
|
|
||||||
```
|
|
||||||
|
|
||||||
## Status: ✅ COMPLETE
|
|
||||||
|
|
||||||
All 4 i18n dependencies installed successfully.
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
# Task 03: Locale File Structure - Evidence
|
|
||||||
|
|
||||||
## Status: ✅ COMPLETE (Pre-existing)
|
|
||||||
|
|
||||||
## Directory Structure Created
|
|
||||||
```
|
|
||||||
src/renderer/src/locales/
|
|
||||||
├── default/
|
|
||||||
│ ├── common.json (31 keys)
|
|
||||||
│ ├── domain.json (31 keys)
|
|
||||||
│ ├── settings.json (24 keys)
|
|
||||||
│ └── errors.json (20 keys)
|
|
||||||
├── zh-CN/
|
|
||||||
│ ├── common.json (31 keys)
|
|
||||||
│ ├── domain.json (31 keys)
|
|
||||||
│ ├── settings.json (24 keys)
|
|
||||||
│ └── errors.json (20 keys)
|
|
||||||
├── ja-JP/
|
|
||||||
│ ├── common.json (31 keys)
|
|
||||||
│ ├── domain.json (31 keys)
|
|
||||||
│ ├── settings.json (24 keys)
|
|
||||||
│ └── errors.json (20 keys)
|
|
||||||
└── en-US/
|
|
||||||
├── common.json (31 keys)
|
|
||||||
├── domain.json (31 keys)
|
|
||||||
├── settings.json (24 keys)
|
|
||||||
└── errors.json (20 keys)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Verification
|
|
||||||
- [x] Directories created: default/, zh-CN/, ja-JP/, en-US/
|
|
||||||
- [x] Files created: common.json, domain.json, settings.json, errors.json
|
|
||||||
- [x] Each file has >5 translation keys (minimum 20 per file)
|
|
||||||
- [x] Flat key structure used (no nested objects)
|
|
||||||
|
|
||||||
## Sample Content
|
|
||||||
|
|
||||||
### common.json (default)
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"appName": "Kintone Manager",
|
|
||||||
"save": "保存",
|
|
||||||
"cancel": "取消",
|
|
||||||
"delete": "删除",
|
|
||||||
"edit": "编辑",
|
|
||||||
...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### domain.json (default)
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"title": "域名管理",
|
|
||||||
"addDomain": "添加域名",
|
|
||||||
"editDomain": "编辑域名",
|
|
||||||
...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### settings.json (default)
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"title": "设置",
|
|
||||||
"language": "语言",
|
|
||||||
"selectLanguage": "选择语言",
|
|
||||||
...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### errors.json (default)
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"networkError": "网络错误",
|
|
||||||
"invalidDomain": "无效的域名",
|
|
||||||
"connectionFailed": "连接失败",
|
|
||||||
...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
- Structure was already in place from prior work
|
|
||||||
- All translations follow flat key structure
|
|
||||||
- Chinese is the default/source language
|
|
||||||
- English and Japanese translations provided
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
# Task 04: Locale Store - Compilation Evidence
|
|
||||||
|
|
||||||
## Date: 2026-03-13
|
|
||||||
|
|
||||||
## Files Created
|
|
||||||
- src/renderer/src/stores/localeStore.ts
|
|
||||||
|
|
||||||
## Verification
|
|
||||||
|
|
||||||
### TypeScript Check
|
|
||||||
```bash
|
|
||||||
npx tsc --noEmit
|
|
||||||
# Result: PASSED (no errors)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Store Implementation
|
|
||||||
- Uses Zustand with persist middleware
|
|
||||||
- Imports LocaleCode and DEFAULT_LOCALE from @shared/types/locale
|
|
||||||
- Persists only the locale state value (partialize pattern)
|
|
||||||
- Exports useLocaleStore hook
|
|
||||||
|
|
||||||
### State Shape
|
|
||||||
```typescript
|
|
||||||
interface LocaleState {
|
|
||||||
locale: LocaleCode; // "zh-CN" | "ja-JP" | "en-US"
|
|
||||||
setLocale: (locale: LocaleCode) => void;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Default Value
|
|
||||||
- locale: "zh-CN" (from DEFAULT_LOCALE constant)
|
|
||||||
|
|
||||||
## Status: COMPLETED
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
TypeScript compilation: SUCCESS
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
# Task 06: Configure @lobehub/i18n-cli
|
|
||||||
|
|
||||||
## Completed Actions
|
|
||||||
|
|
||||||
1. **Installed @lobehub/i18n-cli@^1.26.1** as dev dependency
|
|
||||||
2. **Added npm script**: `"i18n": "lobe-i18n"` to package.json
|
|
||||||
3. **Verified CLI works**: `npm run i18n -- --help` returns usage info
|
|
||||||
|
|
||||||
## Existing Configuration (.i18nrc.js)
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
module.exports = {
|
|
||||||
entry: ['src/renderer/src/locales/default/*.json'],
|
|
||||||
output: 'src/renderer/src/locales',
|
|
||||||
entryLocale: 'zh-CN',
|
|
||||||
outputLocales: ['en-US', 'ja-JP'],
|
|
||||||
apiKey: process.env.OPENAI_API_KEY || '',
|
|
||||||
apiModel: 'gpt-4o-mini',
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
## CLI Usage
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Run translation
|
|
||||||
npm run i18n
|
|
||||||
|
|
||||||
# With markdown translation
|
|
||||||
npm run i18n -- --with-md
|
|
||||||
|
|
||||||
# Lint translations
|
|
||||||
npm run i18n -- --lint
|
|
||||||
```
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
- Source locale: zh-CN (in `locales/default/`)
|
|
||||||
- Output locales: en-US, ja-JP
|
|
||||||
- API key must be set via `OPENAI_API_KEY` environment variable
|
|
||||||
- Uses gpt-4o-mini model for translation
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
# Learnings
|
|
||||||
|
|
||||||
## [2026-03-12] Kintone Customize Manager Core Features
|
|
||||||
|
|
||||||
### Technical Decisions
|
|
||||||
|
|
||||||
1. **Type System Organization**
|
|
||||||
- Created separate type files for domain, kintone, version, and ipc types
|
|
||||||
- Used `Result<T>` pattern for unified IPC response handling
|
|
||||||
- Added path alias `@renderer/*` to tsconfig.node.json for main process imports
|
|
||||||
|
|
||||||
2. **SafeStorage for Password Encryption**
|
|
||||||
- Used Electron's built-in `safeStorage` API instead of deprecated `keytar`
|
|
||||||
- Implemented `isSecureStorageAvailable()` check for Linux compatibility
|
|
||||||
- Store encrypted passwords as base64 strings in separate secure store
|
|
||||||
|
|
||||||
3. **Kintone API Client**
|
|
||||||
- Used native `fetch` API (Node.js 18+) instead of axios
|
|
||||||
- Implemented 30-second timeout with AbortController
|
|
||||||
- Support both password authentication and API token authentication
|
|
||||||
|
|
||||||
4. **IPC Architecture**
|
|
||||||
- All handlers return `{ success: boolean, data?: T, error?: string }`
|
|
||||||
- Used `contextBridge` to expose safe API to renderer
|
|
||||||
- Created typed `ElectronAPI` interface for window.api
|
|
||||||
|
|
||||||
5. **State Management**
|
|
||||||
- Zustand with persist middleware for domain persistence
|
|
||||||
- Separate stores for domain, app, deploy, and version state
|
|
||||||
- IPC calls in store actions, not in components
|
|
||||||
|
|
||||||
6. **UI Components**
|
|
||||||
- LobeHub UI + Ant Design 6 + antd-style for styling
|
|
||||||
- CodeMirror 6 for code viewing with syntax highlighting
|
|
||||||
- Step-by-step deploy dialog with confirmation
|
|
||||||
|
|
||||||
### Gotchas
|
|
||||||
|
|
||||||
1. **tsconfig.node.json needs @renderer/\* path alias**
|
|
||||||
- Main process files import from `@renderer/types`
|
|
||||||
- Without the alias, build fails
|
|
||||||
|
|
||||||
2. **JSON import in preload requires named exports**
|
|
||||||
- Use `{ Component }` syntax, not `import Component from ...`
|
|
||||||
- Default exports don't work with contextBridge
|
|
||||||
|
|
||||||
3. **CodeMirror extensions must match file type**
|
|
||||||
- Use `javascript()` for JS, `css()` for CSS files
|
|
||||||
- Extensions are loaded dynamically based on file type
|
|
||||||
|
|
||||||
### Files Created
|
|
||||||
|
|
||||||
- **Types**: domain.ts, kintone.ts, version.ts, ipc.ts
|
|
||||||
- **Main**: storage.ts, kintone-api.ts, ipc-handlers.ts
|
|
||||||
- **Preload**: index.ts, index.d.ts (updated)
|
|
||||||
- **Stores**: domainStore.ts, appStore.ts, deployStore.ts, versionStore.ts
|
|
||||||
- **Components**: DomainManager/, SpaceTree/, AppDetail/, CodeViewer/, FileUploader/, DeployDialog/, VersionHistory/
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
|
|
||||||
## [2026-03-14] Locale Not Synced Between Processes
|
|
||||||
|
|
||||||
### 问题描述
|
|
||||||
Renderer process 和 Main process 的 locale 状态没有同步。
|
|
||||||
|
|
||||||
### 复现步骤
|
|
||||||
1. 用户在 UI 中切换语言 (例如从 zh-CN 到 en-US)
|
|
||||||
2. localeStore 更新 localStorage,i18next 切换语言
|
|
||||||
3. 但是 Main process 的 `config.json` 仍然是旧值
|
|
||||||
4. Main process 的错误消息使用旧语言
|
|
||||||
|
|
||||||
### 根本原因
|
|
||||||
- `localeStore.setLocale()` 只更新 Zustand state
|
|
||||||
- 没有调用 `window.api.setLocale()` 同步到 Main process
|
|
||||||
|
|
||||||
### 解决方案
|
|
||||||
需要在以下位置添加同步逻辑:
|
|
||||||
|
|
||||||
1. **localeStore.ts**: 修改 `setLocale` action
|
|
||||||
```typescript
|
|
||||||
setLocale: async (locale) => {
|
|
||||||
set({ locale });
|
|
||||||
await window.api.setLocale({ locale });
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **App.tsx**: 在初始化时从 Main process 读取 locale
|
|
||||||
```typescript
|
|
||||||
useEffect(() => {
|
|
||||||
const initLocale = async () => {
|
|
||||||
const result = await window.api.getLocale();
|
|
||||||
if (result.success) {
|
|
||||||
useLocaleStore.getState().setLocale(result.data);
|
|
||||||
i18n.changeLanguage(result.data);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
initLocale();
|
|
||||||
}, []);
|
|
||||||
```
|
|
||||||
|
|
||||||
### 影响范围
|
|
||||||
- `src/renderer/src/stores/localeStore.ts`
|
|
||||||
- `src/renderer/src/App.tsx` 或 `src/renderer/src/main.tsx`
|
|
||||||
|
|
||||||
### 优先级
|
|
||||||
高 - 影响用户体验,Main process 错误消息语言不一致
|
|
||||||
@@ -1,790 +0,0 @@
|
|||||||
# i18n Integration Learnings
|
|
||||||
|
|
||||||
## 2026-03-13 - Locale File Structure
|
|
||||||
|
|
||||||
### Structure Created
|
|
||||||
- **Directory**: `src/renderer/src/locales/`
|
|
||||||
- **Subdirectories**: `default/`, `zh-CN/`, `ja-JP/`, `en-US/`
|
|
||||||
- **Files per language**: `common.json`, `domain.json`, `settings.json`, `errors.json`
|
|
||||||
|
|
||||||
### Translation Key Format
|
|
||||||
- Use flat key structure (no nested objects): `"app.title"` instead of `{"app": {"title": ""}}`
|
|
||||||
- Each file contains 20+ translation keys (exceeds minimum 5)
|
|
||||||
- Keys are organized by feature area:
|
|
||||||
- `common.json`: UI buttons, labels, status messages
|
|
||||||
- `domain.json`: Domain management specific translations
|
|
||||||
- `settings.json`: Settings page translations
|
|
||||||
- `errors.json`: Error messages and validation errors
|
|
||||||
|
|
||||||
### Language Codes
|
|
||||||
- `default/`: Source language (Chinese)
|
|
||||||
- `zh-CN/`: Simplified Chinese
|
|
||||||
- `en-US/`: English (US)
|
|
||||||
- `ja-JP/`: Japanese
|
|
||||||
|
|
||||||
### Best Practices
|
|
||||||
1. Keep translation keys descriptive (e.g., `collapseSidebar` not `cs`)
|
|
||||||
2. Group related keys together in the same file
|
|
||||||
3. Use consistent naming convention (camelCase for keys)
|
|
||||||
## [2026-03-13] - Locale Store Implementation
|
|
||||||
|
|
||||||
### Pattern: Zustand Store with Persist Middleware
|
|
||||||
|
|
||||||
Created `localeStore.ts` following the existing `domainStore.ts` pattern:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
export const useLocaleStore = create<LocaleState>()(
|
|
||||||
persist(
|
|
||||||
(set) => ({
|
|
||||||
locale: DEFAULT_LOCALE,
|
|
||||||
setLocale: (locale) => set({ locale }),
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
name: "locale-storage",
|
|
||||||
partialize: (state) => ({ locale: state.locale }),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
### Key Decisions
|
|
||||||
- Use `partialize` to only persist the `locale` value, not actions
|
|
||||||
- Import `DEFAULT_LOCALE` from shared types to ensure consistency
|
|
||||||
- Store key is `locale-storage` in localStorage
|
|
||||||
|
|
||||||
### File Location
|
|
||||||
- Store: `src/renderer/src/stores/localeStore.ts`
|
|
||||||
- Types: `src/shared/types/locale.ts` (LocaleCode, DEFAULT_LOCALE)
|
|
||||||
|
|
||||||
## [2026-03-13] - i18n Instance Configuration
|
|
||||||
|
|
||||||
### Pattern: Static Import Configuration
|
|
||||||
|
|
||||||
Created `i18n.ts` with static imports for all locale files:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Import locale files statically
|
|
||||||
import commonZHCN from "./locales/zh-CN/common.json";
|
|
||||||
import domainZHCN from "./locales/zh-CN/domain.json";
|
|
||||||
// ... (all 12 files imported)
|
|
||||||
|
|
||||||
const resources = {
|
|
||||||
"zh-CN": { common: commonZHCN, domain: domainZHCN, ... },
|
|
||||||
"ja-JP": { ... },
|
|
||||||
"en-US": { ... },
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### Key Configuration Options
|
|
||||||
|
|
||||||
- **fallbackLng**: `zh-CN` - fallback to Chinese if translation missing
|
|
||||||
- **defaultNS**: `common` - default namespace for `t()` calls
|
|
||||||
- **ns**: `['common', 'domain', 'settings', 'errors']` - 4 namespaces
|
|
||||||
- **escapeValue**: `false` - React handles XSS protection
|
|
||||||
- **detection**: localStorage + navigator order, caches to localStorage
|
|
||||||
|
|
||||||
### Language Detector Configuration
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
detection: {
|
|
||||||
order: ["localStorage", "navigator"],
|
|
||||||
caches: ["localStorage"],
|
|
||||||
lookupLocalStorage: "i18nextLng",
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This ensures:
|
|
||||||
1. First check localStorage for saved preference
|
|
||||||
2. Fall back to browser language
|
|
||||||
3. Persist detected/selected language to localStorage
|
|
||||||
|
|
||||||
### File Location
|
|
||||||
- Configuration: `src/renderer/src/i18n.ts`
|
|
||||||
- Must be imported in `main.tsx` before React renders
|
|
||||||
|
|
||||||
## [2026-03-13] - Dependencies Installation
|
|
||||||
|
|
||||||
### Installed Packages
|
|
||||||
- `i18next@25.8.18` - Core i18n framework
|
|
||||||
- `react-i18next@16.5.8` - React bindings for i18next
|
|
||||||
- `i18next-browser-languagedetector@8.2.1` - Browser language detection
|
|
||||||
- `@lobehub/i18n-cli@1.26.1` - LobeHub i18n CLI tool
|
|
||||||
|
|
||||||
### Notes
|
|
||||||
- React-i18next correctly dedupes i18next dependency
|
|
||||||
- All packages are latest stable versions
|
|
||||||
- LobeHub UI uses @emoji-mart/react which has peer dependency warning for React 19 (non-blocking)
|
|
||||||
|
|
||||||
## [2026-03-13] - @lobehub/i18n-cli Configuration
|
|
||||||
|
|
||||||
### Configuration Pattern
|
|
||||||
- Binary name: `lobe-i18n` (not `@lobehub/i18n-cli`)
|
|
||||||
- Config file: `.i18nrc.js` (CommonJS format)
|
|
||||||
- Uses environment variable for API key: `OPENAI_API_KEY`
|
|
||||||
|
|
||||||
### Locale Structure for CLI
|
|
||||||
- `locales/default/` - Source files (Chinese)
|
|
||||||
- `locales/zh-CN/` - Same as default (for consistency)
|
|
||||||
- `locales/en-US/` - English translations
|
|
||||||
- `locales/ja-JP/` - Japanese translations
|
|
||||||
|
|
||||||
### Important Notes
|
|
||||||
- entryLocale = source language (zh-CN = Chinese)
|
|
||||||
- outputLocales = target languages for AI translation
|
|
||||||
- Do NOT put zh-CN in outputLocales if it's the source
|
|
||||||
- The CLI supports markdown translation with `--with-md` flag
|
|
||||||
|
|
||||||
### npm script
|
|
||||||
```json
|
|
||||||
"i18n": "lobe-i18n"
|
|
||||||
```
|
|
||||||
|
|
||||||
Run with: `npm run i18n`
|
|
||||||
## 2026-03-14 - I18nextProvider Integration
|
|
||||||
|
|
||||||
### Changes Made
|
|
||||||
- Added `I18nextProvider` import from `react-i18next`
|
|
||||||
- Added `i18n` instance import from `./i18n`
|
|
||||||
- Wrapped `<ThemeProvider>` with `<I18nextProvider i18n={i18n}>` to enable i18n throughout the app
|
|
||||||
|
|
||||||
### Integration Pattern
|
|
||||||
```tsx
|
|
||||||
<I18nextProvider i18n={i18n}>
|
|
||||||
<ThemeProvider>
|
|
||||||
<AntdApp>
|
|
||||||
<App />
|
|
||||||
</AntdApp>
|
|
||||||
</ThemeProvider>
|
|
||||||
</I18nextProvider>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Notes
|
|
||||||
- The i18n instance from `./i18n` is already initialized (chained `.use().init()`)
|
|
||||||
- No additional initialization needed in main.tsx
|
|
||||||
- I18nextProvider wraps ThemeProvider (not the other way around)
|
|
||||||
|
|
||||||
- I18nextProvider wraps ThemeProvider (not the other way around)
|
|
||||||
|
|
||||||
## [2026-03-14] - Ant Design Locale Synchronization
|
|
||||||
|
|
||||||
### Pattern: Locale Mapping
|
|
||||||
- Use a mapping function to convert i18next locale codes to Ant Design locale objects
|
|
||||||
- Supported mapping:
|
|
||||||
- `zh-CN` → `zhCN` (antd/locale/zh_CN)
|
|
||||||
- `ja-JP` → `jaJP` (antd/locale/ja_JP)
|
|
||||||
- `en-US` → `enUS` (antd/locale/en_US)
|
|
||||||
|
|
||||||
### Implementation
|
|
||||||
```typescript
|
|
||||||
// Import all locales
|
|
||||||
import zhCN from "antd/locale/zh_CN";
|
|
||||||
import jaJP from "antd/locale/ja_JP";
|
|
||||||
import enUS from "antd/locale/en_US";
|
|
||||||
import type { Locale } from "antd/es/locale";
|
|
||||||
|
|
||||||
// Map locale code to Ant Design locale
|
|
||||||
const getAntdLocale = React.useCallback((localeCode: string): Locale => {
|
|
||||||
switch (localeCode) {
|
|
||||||
case "ja-JP":
|
|
||||||
return jaJP;
|
|
||||||
case "en-US":
|
|
||||||
return enUS;
|
|
||||||
case "zh-CN":
|
|
||||||
default:
|
|
||||||
return zhCN;
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Memoize the result
|
|
||||||
const antdLocale = React.useMemo(
|
|
||||||
() => getAntdLocale(locale),
|
|
||||||
[locale, getAntdLocale]
|
|
||||||
);
|
|
||||||
|
|
||||||
// Use in ConfigProvider
|
|
||||||
<ConfigProvider locale={antdLocale}>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Key Points
|
|
||||||
- Use `React.useCallback` for the mapping function to prevent unnecessary re-renders
|
|
||||||
- Use `React.useMemo` to memoize the locale result based on locale changes
|
|
||||||
- Import `Locale` type from `antd/es/locale` for type safety
|
|
||||||
- Default fallback to `zhCN` for unsupported locales
|
|
||||||
|
|
||||||
## [2026-03-14] - Preload Locale API Exposure
|
|
||||||
|
|
||||||
### Files Modified
|
|
||||||
- `src/shared/types/ipc.ts` - Added `SetLocaleParams` interface
|
|
||||||
- `src/preload/index.ts` - Added `getLocale` and `setLocale` IPC invocations
|
|
||||||
- `src/preload/index.d.ts` - Added type declarations for locale API
|
|
||||||
|
|
||||||
### Pattern: IPC Exposure in Preload
|
|
||||||
```typescript
|
|
||||||
// In preload/index.ts
|
|
||||||
const api: SelfAPI = {
|
|
||||||
// ... other APIs
|
|
||||||
|
|
||||||
// Locale
|
|
||||||
getLocale: () => ipcRenderer.invoke("getLocale"),
|
|
||||||
setLocale: (params) => ipcRenderer.invoke("setLocale", params),
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### Type Declaration Pattern
|
|
||||||
```typescript
|
|
||||||
// In preload/index.d.ts
|
|
||||||
import type { SetLocaleParams } from "@shared/types/ipc";
|
|
||||||
import type { LocaleCode } from "@shared/types/locale";
|
|
||||||
|
|
||||||
export interface SelfAPI {
|
|
||||||
// ... other methods
|
|
||||||
|
|
||||||
// ==================== Locale ====================
|
|
||||||
getLocale: () => Promise<Result<LocaleCode>>;
|
|
||||||
setLocale: (params: SetLocaleParams) => Promise<Result<void>>;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Key Points
|
|
||||||
- Follow existing IPC patterns (invoke with channel name and params)
|
|
||||||
- Use `Result<T>` wrapper for return types
|
|
||||||
- Import types from `@shared/types/` path alias
|
|
||||||
- Add IPC type params interface to `ipc.ts`
|
|
||||||
|
|
||||||
## 2026-03-14 - Main Process IPC Locale Synchronization
|
|
||||||
|
|
||||||
### Implementation Pattern
|
|
||||||
|
|
||||||
**Storage Layer** (`src/main/storage.ts`):
|
|
||||||
- Added `locale?: LocaleCode` to `AppConfig` interface
|
|
||||||
- Implemented `getLocale()` - reads locale from config.json, returns `DEFAULT_LOCALE` if not set
|
|
||||||
- Implemented `setLocale(locale: LocaleCode)` - saves locale to config.json
|
|
||||||
- Uses existing `readJsonFile`/`writeJsonFile` pattern for consistency
|
|
||||||
|
|
||||||
**IPC Handlers** (`src/main/ipc-handlers.ts`):
|
|
||||||
- `getLocale` handler: Returns `Promise<Result<LocaleCode>>`
|
|
||||||
- `setLocale` handler: Takes `SetLocaleParams`, returns `Promise<Result<void>>`
|
|
||||||
- Uses existing `handle<P, T>` helper wrapper for error handling
|
|
||||||
|
|
||||||
**Types** (`src/shared/types/ipc.ts`):
|
|
||||||
- `SetLocaleParams` interface already exists with `locale: LocaleCode` property
|
|
||||||
- Follows pattern of other params objects (e.g., `CreateDomainParams`, `UpdateDomainParams`)
|
|
||||||
|
|
||||||
**Preload** (`src/preload/index.ts`):
|
|
||||||
- `getLocale: () => ipcRenderer.invoke("getLocale")`
|
|
||||||
- `setLocale: (params) => ipcRenderer.invoke("setLocale", params)`
|
|
||||||
|
|
||||||
### Key Decisions
|
|
||||||
|
|
||||||
1. **Not using react-i18next in main process**: Main process uses simple locale string storage, not full i18n library
|
|
||||||
2. **Params object pattern**: `setLocale` uses `SetLocaleParams` object instead of `LocaleCode` directly for consistency with other IPC handlers
|
|
||||||
3. **Default fallback**: `getLocale()` returns `DEFAULT_LOCALE` ("zh-CN") when no locale is set
|
|
||||||
4. **Storage location**: Locale stored in `config.json` alongside domains array
|
|
||||||
|
|
||||||
### File Changes Summary
|
|
||||||
|
|
||||||
- `src/main/storage.ts`: Added `getLocale()` and `setLocale()` functions
|
|
||||||
- `src/main/ipc-handlers.ts`: Added `registerGetLocale()` and `registerSetLocale()` handlers
|
|
||||||
- `src/shared/types/ipc.ts`: `SetLocaleParams` already existed
|
|
||||||
- `src/preload/index.d.ts`: Locale API types already existed
|
|
||||||
- `src/preload/index.ts`: Locale methods already existed
|
|
||||||
|
|
||||||
## 2026-03-14 - App.tsx Internationalization
|
|
||||||
|
|
||||||
### Pattern Used
|
|
||||||
- Import: `import { useTranslation } from "react-i18next";`
|
|
||||||
- Hook usage: `const { t } = useTranslation();`
|
|
||||||
- Translation call: `{t('translationKey')}`
|
|
||||||
|
|
||||||
### Translation Keys Added
|
|
||||||
- `deployFiles` - "部署文件" / "Deploy Files" / "ファイルをデプロイ"
|
|
||||||
- `versionHistory` - "版本历史" / "Version History" / "バージョン履歴"
|
|
||||||
- `settings` - "设置" / "Settings" / "設定"
|
|
||||||
|
|
||||||
### Existing Keys Used
|
|
||||||
- `collapseSidebar` - "收起侧边栏"
|
|
||||||
- `expandSidebar` - "展开侧边栏"
|
|
||||||
|
|
||||||
### Files Modified
|
|
||||||
1. `src/renderer/src/App.tsx` - Added useTranslation hook, replaced hardcoded text
|
|
||||||
2. `src/renderer/src/locales/zh-CN/common.json` - Added new keys
|
|
||||||
3. `src/renderer/src/locales/en-US/common.json` - Added new keys
|
|
||||||
4. `src/renderer/src/locales/ja-JP/common.json` - Added new keys
|
|
||||||
5. `src/renderer/src/locales/default/common.json` - Added new keys
|
|
||||||
|
|
||||||
### i18n Setup
|
|
||||||
- Uses `react-i18next` with `I18nextProvider` wrapper in main.tsx
|
|
||||||
- Default namespace: `common`
|
|
||||||
- Fallback language: `zh-CN`
|
|
||||||
- Locale files: `./locales/{lang}/{namespace}.json`
|
|
||||||
|
|
||||||
## [2026-03-14] - DomainManager Component Internationalization
|
|
||||||
|
|
||||||
### Files Modified
|
|
||||||
- `src/renderer/src/components/DomainManager/DomainManager.tsx`
|
|
||||||
- `src/renderer/src/locales/default/domain.json`
|
|
||||||
|
|
||||||
### Pattern: useTranslation Hook with Namespace
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
|
|
||||||
const DomainManager: React.FC<DomainManagerProps> = ({...}) => {
|
|
||||||
const { t } = useTranslation("domain");
|
|
||||||
// ...
|
|
||||||
return <h2>{t("domainManagement")}</h2>;
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### Translation Keys Added
|
|
||||||
- `noDomainSelected`: "未选择 Domain"
|
|
||||||
- `addDomainTooltip`: "添加 Domain"
|
|
||||||
- `domainManagement`: "Domain 管理"
|
|
||||||
- `add`: "添加"
|
|
||||||
- `noDomainConfig`: "暂无 Domain 配置"
|
|
||||||
- `addFirstDomainConfig`: "添加第一个 Domain"
|
|
||||||
|
|
||||||
### Key Points
|
|
||||||
1. Use `useTranslation("domain")` to specify the namespace
|
|
||||||
2. Replace all hardcoded Chinese text with `t("key")` calls
|
|
||||||
3. Use regex `[\u4e00-\u9fff]` to find remaining Chinese characters for verification
|
|
||||||
4. Keep translation keys in camelCase format
|
|
||||||
|
|
||||||
## [2026-03-14] - Main Process Error Message Internationalization
|
|
||||||
|
|
||||||
### Challenge: Cannot Use react-i18next in Main Process
|
|
||||||
|
|
||||||
The main process cannot use `react-i18next` because:
|
|
||||||
1. It's designed for React rendering, not Node.js/Electron main process
|
|
||||||
2. Main process needs synchronous error message access
|
|
||||||
3. Main process errors can be thrown before renderer initializes
|
|
||||||
|
|
||||||
### Solution: Simple Custom i18n Module
|
|
||||||
|
|
||||||
Created `src/main/errors.ts` with a simple translation approach:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import type { LocaleCode } from "@shared/types/locale";
|
|
||||||
import { getLocale } from "./storage";
|
|
||||||
|
|
||||||
const errorMessages: Record<LocaleCode, Record<MainErrorKey, string>> = {
|
|
||||||
"zh-CN": { domainNotFound: "域名未找到", ... },
|
|
||||||
"en-US": { domainNotFound: "Domain not found", ... },
|
|
||||||
"ja-JP": { domainNotFound: "ドメインが見つかりません", ... },
|
|
||||||
};
|
|
||||||
|
|
||||||
export function getErrorMessage(
|
|
||||||
key: MainErrorKey,
|
|
||||||
params?: ErrorParams,
|
|
||||||
locale?: LocaleCode,
|
|
||||||
): string {
|
|
||||||
const targetLocale = locale ?? getLocale();
|
|
||||||
const messages = errorMessages[targetLocale] || errorMessages["zh-CN"];
|
|
||||||
return interpolate(messages[key], params);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Files Modified
|
|
||||||
|
|
||||||
1. `src/main/errors.ts` - NEW: Error message module with translations
|
|
||||||
2. `src/main/ipc-handlers.ts` - Updated all error throws to use `getErrorMessage()`
|
|
||||||
3. `src/main/kintone-api.ts` - Updated fallback errors to use i18n
|
|
||||||
|
|
||||||
### Error Keys Added
|
|
||||||
|
|
||||||
- `domainNotFound` - Domain not found errors
|
|
||||||
- `domainDuplicate` - Duplicate domain+username errors
|
|
||||||
- `connectionFailed` - Connection test failures
|
|
||||||
- `unknownError` - Generic fallback error
|
|
||||||
- `rollbackNotImplemented` - Feature not implemented error
|
|
||||||
- `encryptPasswordFailed` - Password encryption errors
|
|
||||||
- `decryptPasswordFailed` - Password decryption errors
|
|
||||||
|
|
||||||
### Circular Dependency Consideration
|
|
||||||
|
|
||||||
**IMPORTANT**: `errors.ts` imports `getLocale` from `storage.ts`. Therefore, `storage.ts` CANNOT import from `errors.ts`.
|
|
||||||
|
|
||||||
- `storage.ts` password encrypt/decrypt errors remain hardcoded (they are internal system errors)
|
|
||||||
- Only user-facing errors in IPC handlers are internationalized
|
|
||||||
|
|
||||||
### Interpolation Pattern
|
|
||||||
|
|
||||||
For errors with dynamic values, use `{{placeholder}}` syntax:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// In errors.ts
|
|
||||||
const messages = {
|
|
||||||
domainDuplicate: "Domain \"{{domain}}\" with user \"{{username}}\" already exists.",
|
|
||||||
};
|
|
||||||
|
|
||||||
// Usage
|
|
||||||
getErrorMessage("domainDuplicate", { domain: "example.com", username: "admin" });
|
|
||||||
```
|
|
||||||
|
|
||||||
### Test Verification
|
|
||||||
|
|
||||||
Tests show i18n working correctly:
|
|
||||||
```
|
|
||||||
Invalid credentials test result: { success: false, error: '连接失败' }
|
|
||||||
```
|
|
||||||
The error message '连接失败' is in Chinese (the current locale setting).
|
|
||||||
|
|
||||||
|
|
||||||
## [2026-03-14] Locale Persistence Verification
|
|
||||||
|
|
||||||
### 验证结果
|
|
||||||
|
|
||||||
#### ✅ Renderer Process Persistence (正常)
|
|
||||||
|
|
||||||
1. **localeStore** (`src/renderer/src/stores/localeStore.ts`)
|
|
||||||
- 使用 Zustand 的 `persist` 中间件
|
|
||||||
- localStorage key: `locale-storage`
|
|
||||||
- 只持久化 `locale` 字段 (通过 `partialize`)
|
|
||||||
- 实现正确
|
|
||||||
|
|
||||||
2. **i18next** (`src/renderer/src/i18n.ts`)
|
|
||||||
- 使用 `i18next-browser-languagedetector`
|
|
||||||
- localStorage key: `i18nextLng`
|
|
||||||
- 检测顺序: localStorage → navigator
|
|
||||||
- 实现正确
|
|
||||||
|
|
||||||
#### ✅ Main Process Persistence (正常)
|
|
||||||
|
|
||||||
1. **storage.ts** (`src/main/storage.ts`)
|
|
||||||
- `getLocale()`: 从 `config.json` 读取 locale
|
|
||||||
- `setLocale()`: 写入 `config.json`
|
|
||||||
- 默认值: `DEFAULT_LOCALE` (zh-CN)
|
|
||||||
- 实现正确
|
|
||||||
|
|
||||||
2. **IPC Handlers** (`src/main/ipc-handlers.ts`)
|
|
||||||
- `registerGetLocale()`: 返回存储的 locale
|
|
||||||
- `registerSetLocale()`: 保存 locale 到 config.json
|
|
||||||
- 实现正确
|
|
||||||
|
|
||||||
3. **Error Messages** (`src/main/errors.ts`)
|
|
||||||
- `getErrorMessage()`: 使用 `getLocale()` 获取当前语言
|
|
||||||
- 支持错误消息本地化
|
|
||||||
- 实现正确
|
|
||||||
|
|
||||||
#### ❌ CRITICAL ISSUE: Renderer 和 Main Process 没有同步!
|
|
||||||
|
|
||||||
**问题**:
|
|
||||||
- Renderer 修改语言时,只更新 localStorage,**没有调用 `window.api.setLocale()`**
|
|
||||||
- Main process 的 `config.json` 与 localStorage 不同步
|
|
||||||
- Main process 错误消息可能使用错误的语言
|
|
||||||
|
|
||||||
**证据**:
|
|
||||||
- `localeStore.ts` 的 `setLocale` action 只更新 Zustand state
|
|
||||||
- `App.tsx` 使用 `useLocaleStore().locale` 但没有同步到 main process
|
|
||||||
- `i18n.ts` 的 LanguageDetector 只检测 localStorage,不涉及 main process
|
|
||||||
|
|
||||||
**影响**:
|
|
||||||
- 重启应用后,main process 的错误消息语言可能与 UI 不一致
|
|
||||||
- `getErrorMessage()` 会使用 `config.json` 中可能过时的 locale
|
|
||||||
|
|
||||||
### 修复建议
|
|
||||||
|
|
||||||
需要在 renderer 和 main process 之间建立同步机制:
|
|
||||||
|
|
||||||
1. **方案 A (推荐): App 启动时同步**
|
|
||||||
- 在 App 初始化时,读取 main process 的 locale
|
|
||||||
- 设置 localeStore 和 i18next
|
|
||||||
- 用户修改语言时,同时调用 `window.api.setLocale()`
|
|
||||||
|
|
||||||
2. **方案 B: 双向绑定**
|
|
||||||
- localeStore 的 `setLocale` 同时调用 IPC
|
|
||||||
- 使用 useEffect 监听 locale 变化并同步
|
|
||||||
|
|
||||||
### 首次启动处理
|
|
||||||
|
|
||||||
当前实现已经正确处理:
|
|
||||||
- `getLocale()` 返回 `DEFAULT_LOCALE` 如果没有存储
|
|
||||||
- i18next 的 detector 会尝试使用系统语言 (`navigator`)
|
|
||||||
- 首次启动会使用系统语言 (如果支持) 或 fallback 到 zh-CN
|
|
||||||
|
|
||||||
## [2026-03-14] - Settings Component with Language Switcher
|
|
||||||
|
|
||||||
### Component Structure
|
|
||||||
- **Directory**: `src/renderer/src/components/Settings/`
|
|
||||||
- **Files**: `Settings.tsx`, `index.ts`
|
|
||||||
- **Pattern**: Functional component with antd-style
|
|
||||||
|
|
||||||
### Implementation Pattern
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
import { Radio, Typography } from "antd";
|
|
||||||
import { createStyles } from "antd-style";
|
|
||||||
import { useLocaleStore } from "@renderer/stores/localeStore";
|
|
||||||
import { LOCALES, type LocaleCode } from "@shared/types/locale";
|
|
||||||
|
|
||||||
const Settings: React.FC = () => {
|
|
||||||
const { t } = useTranslation("settings");
|
|
||||||
const { styles } = useStyles();
|
|
||||||
const { locale, setLocale } = useLocaleStore();
|
|
||||||
const i18n = useTranslation().i18n;
|
|
||||||
|
|
||||||
const handleLocaleChange = (newLocale: LocaleCode) => {
|
|
||||||
setLocale(newLocale); // Update Zustand store
|
|
||||||
i18n.changeLanguage(newLocale); // Update i18next
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Radio.Group value={locale} onChange={(e) => handleLocaleChange(e.target.value)}>
|
|
||||||
{LOCALES.map((loc) => (
|
|
||||||
<Radio key={loc.code} value={loc.code}>
|
|
||||||
{loc.nativeName}
|
|
||||||
</Radio>
|
|
||||||
))}
|
|
||||||
</Radio.Group>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### Key Design Decisions
|
|
||||||
|
|
||||||
1. **Use LOCALES constant**: Import from `@shared/types/locale` for consistent locale data
|
|
||||||
2. **Dual update**: Update both localeStore and i18n when language changes
|
|
||||||
3. **Radio.Group styling**: Custom CSS for better UX with native name and English name display
|
|
||||||
4. **Namespace usage**: Use `useTranslation("settings")` for settings-specific translations
|
|
||||||
|
|
||||||
### Translation Keys Used
|
|
||||||
- `settings.json`: `language` - "语言" / "Language" / "言語"
|
|
||||||
|
|
||||||
### UI Design
|
|
||||||
- Radio options styled as cards with border
|
|
||||||
- Shows both native name (e.g., "简体中文") and English name (e.g., "Chinese Simplified")
|
|
||||||
- Hover effect with primary color border and background
|
|
||||||
- Selected state highlighted with primary color
|
|
||||||
|
|
||||||
### Note on Synchronization
|
|
||||||
The component updates both `localeStore` and `i18n`, but does NOT call `window.api.setLocale()` to sync with main process. This is a known limitation documented in the learnings file above. Future work should add main process sync.
|
|
||||||
### Note on Synchronization
|
|
||||||
The component updates both `localeStore` and `i18n`, but does NOT call `window.api.setLocale()` to sync with main process. This is a known limitation documented in the learnings file above. Future work should add main process sync.
|
|
||||||
|
|
||||||
## 2026-03-14 - Component Internationalization (Wave 3)
|
|
||||||
|
|
||||||
### New Namespaces Created
|
|
||||||
- `app.json` - AppDetail, AppList components
|
|
||||||
- `deploy.json` - DeployDialog component
|
|
||||||
- `file.json` - FileUploader, CodeViewer components
|
|
||||||
- `version.json` - VersionHistory component
|
|
||||||
|
|
||||||
### Translation Key Naming Convention
|
|
||||||
- Actions: `loadApps`, `saveConfig`, `testConnection`
|
|
||||||
- States: `loading`, `connected`, `deploying`
|
|
||||||
- Labels: `fileName`, `position`, `type`
|
|
||||||
- Messages: `loadAppsFailed`, `deploySuccess`
|
|
||||||
|
|
||||||
### Cross-Namespace Reference Pattern
|
|
||||||
```typescript
|
|
||||||
// Reference other namespace's translations
|
|
||||||
t("cancel", { ns: "common" })
|
|
||||||
t("selectApp", { ns: "app" })
|
|
||||||
```
|
|
||||||
|
|
||||||
### Interpolation Pattern
|
|
||||||
```typescript
|
|
||||||
// JSON file
|
|
||||||
"totalApps": "共 {{count}} 个应用"
|
|
||||||
|
|
||||||
// Component usage
|
|
||||||
t("totalApps", { count: displayApps.length })
|
|
||||||
```
|
|
||||||
|
|
||||||
### Components Internationalized
|
|
||||||
1. **DomainManager** - domain namespace
|
|
||||||
2. **DomainForm** - domain namespace
|
|
||||||
3. **DomainList** - domain namespace
|
|
||||||
4. **AppDetail** - app namespace
|
|
||||||
5. **AppList** - app namespace
|
|
||||||
6. **CodeViewer** - file namespace
|
|
||||||
7. **DeployDialog** - deploy namespace
|
|
||||||
8. **FileUploader** - file namespace
|
|
||||||
9. **VersionHistory** - version namespace
|
|
||||||
|
|
||||||
### i18n.ts Update Pattern
|
|
||||||
When adding new namespaces:
|
|
||||||
1. Add imports for all locales
|
|
||||||
2. Add to resources object for each language
|
|
||||||
3. Add to `ns` array
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Example
|
|
||||||
import appZHCN from "./locales/zh-CN/app.json";
|
|
||||||
// ...
|
|
||||||
const resources = {
|
|
||||||
"zh-CN": { ..., app: appZHCN, ... },
|
|
||||||
// ...
|
|
||||||
};
|
|
||||||
// ...
|
|
||||||
ns: ["common", "domain", "settings", "errors", "app", "deploy", "file", "version"],
|
|
||||||
```
|
|
||||||
|
|
||||||
## [2026-03-14] - Renderer/Main Process Locale Synchronization Fix
|
|
||||||
|
|
||||||
### Problem
|
|
||||||
Renderer stored locale in localStorage (via Zustand persist), main process stored in config.json - they were NOT synced. When user changed language in UI, main process error messages still used old language.
|
|
||||||
|
|
||||||
### Solution: Bidirectional Sync
|
|
||||||
|
|
||||||
**1. Settings.tsx - Sync to Main Process on Change**
|
|
||||||
```typescript
|
|
||||||
const handleLocaleChange = async (newLocale: LocaleCode) => {
|
|
||||||
setLocale(newLocale);
|
|
||||||
i18n.changeLanguage(newLocale);
|
|
||||||
// Sync locale to main process
|
|
||||||
await window.api.setLocale({ locale: newLocale });
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
**2. App.tsx - Sync from Main Process on Mount**
|
|
||||||
```typescript
|
|
||||||
const setLocaleStore = useLocaleStore((state) => state.setLocale);
|
|
||||||
|
|
||||||
// Sync locale from main process on mount
|
|
||||||
React.useEffect(() => {
|
|
||||||
const syncLocaleFromMain = async () => {
|
|
||||||
const result = await window.api.getLocale();
|
|
||||||
if (result.success && result.data) {
|
|
||||||
setLocaleStore(result.data);
|
|
||||||
i18n.changeLanguage(result.data);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
syncLocaleFromMain();
|
|
||||||
}, [setLocaleStore]);
|
|
||||||
```
|
|
||||||
|
|
||||||
### Key Points
|
|
||||||
1. **On language change**: Update localStorage (Zustand), i18next, AND main process config.json
|
|
||||||
2. **On app startup**: Read locale from main process and sync to renderer
|
|
||||||
3. **Use async/await**: IPC calls are asynchronous
|
|
||||||
4. **Import i18n directly**: Need direct reference to i18n instance for changeLanguage() in useEffect
|
|
||||||
|
|
||||||
### Files Modified
|
|
||||||
- `src/renderer/src/components/Settings/Settings.tsx` - Added `window.api.setLocale()` call
|
|
||||||
- `src/renderer/src/App.tsx` - Added useEffect to sync from main process on mount
|
|
||||||
```
|
|
||||||
|
|
||||||
## [2026-03-14] - Code Quality Review - Critical Parsing Errors Found
|
|
||||||
|
|
||||||
### VERDICT: FAIL
|
|
||||||
|
|
||||||
| Check | Status | Count |
|
|
||||||
|-------|--------|-------|
|
|
||||||
| TypeScript | PASS | 0 errors |
|
|
||||||
| ESLint | FAIL | 11 parsing errors, 1 warning |
|
|
||||||
| `as any` | PASS | 0 found |
|
|
||||||
| `@ts-ignore` | WARNING | 2 found (acceptable) |
|
|
||||||
| Empty catches | PASS | 0 found |
|
|
||||||
|
|
||||||
### Critical Issues (P0 - Parsing Errors)
|
|
||||||
|
|
||||||
**Root Cause**: Incomplete i18n integration - leftover duplicate code from merging translated and untranslated code versions.
|
|
||||||
|
|
||||||
#### 1. Duplicate `import {` statements (5 files)
|
|
||||||
All files have duplicate `import {` on lines 8-9:
|
|
||||||
- `src/renderer/src/components/AppDetail/AppDetail.tsx`
|
|
||||||
- `src/renderer/src/components/AppList/AppList.tsx`
|
|
||||||
- `src/renderer/src/components/DeployDialog/DeployDialog.tsx`
|
|
||||||
- `src/renderer/src/components/VersionHistory/VersionHistory.tsx`
|
|
||||||
|
|
||||||
#### 2. Duplicate function parameters (2 files)
|
|
||||||
Parameters duplicated inside function body:
|
|
||||||
- `src/renderer/src/components/CodeViewer/CodeViewer.tsx` (lines 68-72)
|
|
||||||
- `src/renderer/src/components/FileUploader/FileUploader.tsx` (lines 68-72)
|
|
||||||
|
|
||||||
#### 3. Duplicate code blocks (2 files)
|
|
||||||
- `src/main/ipc-handlers.ts` (lines 127-128): Duplicate error message string - leftover hardcoded Chinese
|
|
||||||
- `src/renderer/src/components/DomainManager/DomainForm.tsx` (lines 166-169): Duplicate `else` block with hardcoded Chinese text
|
|
||||||
|
|
||||||
### ESLint Warning (P3)
|
|
||||||
- `src/renderer/src/App.tsx:242` - Missing dependency `setIsResizing` in useCallback
|
|
||||||
|
|
||||||
### Acceptable @ts-ignore (P2)
|
|
||||||
- `src/preload/index.ts:50,52` - Used for non-isolated context fallback (acceptable)
|
|
||||||
|
|
||||||
### Prevention
|
|
||||||
- After large-scale refactoring (like i18n integration), always run `npm run lint` before committing
|
|
||||||
- Use automated checks in CI/CD pipeline
|
|
||||||
- Code review should catch duplicate code blocks
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## [2026-03-14] - Scope Fidelity Check Results
|
|
||||||
|
|
||||||
### Must Have Compliance [5/5 PASS]
|
|
||||||
|
|
||||||
| Requirement | Status | Evidence |
|
|
||||||
|-------------|--------|----------|
|
|
||||||
| react-i18next + i18next 核心库 | ✅ PASS | `package.json`: i18next@25.8.18, react-i18next@16.5.8 |
|
|
||||||
| @lobehub/i18n-cli 自动化翻译 | ✅ PASS | `package.json` devDeps: @lobehub/i18n-cli@1.26.1, `.i18nrc.js` configured |
|
|
||||||
| 中日英三语完整翻译 | ✅ PASS | 32 locale files across zh-CN/, ja-JP/, en-US/ with 8 namespaces each |
|
|
||||||
| 语言切换 UI 组件 | ✅ PASS | `src/renderer/src/components/Settings/Settings.tsx` with Radio.Group |
|
|
||||||
| 用户偏好持久化 | ✅ PASS | `localeStore.ts` with Zustand persist, `storage.ts` getLocale/setLocale |
|
|
||||||
|
|
||||||
### Must NOT Have Compliance [4/4 PASS]
|
|
||||||
|
|
||||||
| Forbidden Pattern | Status | Evidence |
|
|
||||||
|-------------------|--------|----------|
|
|
||||||
| i18next-electron-fs-backend | ✅ PASS | Not found in dependencies or code (grep returned 0 matches) |
|
|
||||||
| RTL 语言支持 | ✅ PASS | No RTL/direction code found (grep returned 0 matches) |
|
|
||||||
| 远程翻译文件加载 | ✅ PASS | Using static imports in `i18n.ts`, no HTTP backend |
|
|
||||||
| MVP 阶段过度抽象翻译 key | ✅ PASS | Flat key structure, reasonable naming convention |
|
|
||||||
|
|
||||||
### Tasks Compliance [17/17 PASS]
|
|
||||||
|
|
||||||
All 17 tasks from the plan have been implemented:
|
|
||||||
- Wave 1 (Tasks 1-6): Dependencies, types, locales, store, i18n config, CLI config
|
|
||||||
- Wave 2 (Tasks 7-10): Provider, AntD locale sync, IPC handlers, Preload API
|
|
||||||
- Wave 3 (Tasks 11-14): Component i18n, main process errors
|
|
||||||
- Wave 4 (Tasks 15-17): Settings page, language switcher, persistence
|
|
||||||
|
|
||||||
### Code Quality Issues Found
|
|
||||||
|
|
||||||
⚠️ **CRITICAL: Duplicate Code Blocks**
|
|
||||||
|
|
||||||
The following files contain duplicate code blocks that need cleanup:
|
|
||||||
|
|
||||||
1. **`src/renderer/src/i18n.ts`**:
|
|
||||||
- Lines 14-17 duplicate lines 6-13 (imports)
|
|
||||||
- Lines 26-28 duplicate lines 18-25 (imports)
|
|
||||||
- Lines 38-40 duplicate lines 30-37 (imports)
|
|
||||||
- Lines 75-94 duplicate lines 43-74 (resources object)
|
|
||||||
|
|
||||||
2. **`src/renderer/src/components/Settings/Settings.tsx`**:
|
|
||||||
- Lines 81-83 duplicate lines 76-80 (handleLocaleChange function)
|
|
||||||
|
|
||||||
3. **`src/renderer/src/App.tsx`**:
|
|
||||||
- Lines 159-160 duplicate line 158 (`const { styles } = useStyles();`)
|
|
||||||
- Lines 191-192 duplicate lines 176-177 (useState declarations)
|
|
||||||
|
|
||||||
4. **`src/main/ipc-handlers.ts`**:
|
|
||||||
- Lines 127-129 contain incomplete/duplicate code block after getErrorMessage call
|
|
||||||
|
|
||||||
5. **`src/renderer/src/main.tsx`**:
|
|
||||||
- Line 14: Ant Design locale hardcoded as `locale={zhCN}` instead of dynamic
|
|
||||||
|
|
||||||
### VERDICT
|
|
||||||
|
|
||||||
**Must Have**: 5/5 ✅ PASS
|
|
||||||
**Must NOT Have**: 4/4 ✅ PASS
|
|
||||||
**Tasks**: 17/17 ✅ PASS
|
|
||||||
|
|
||||||
**SCOPE FIDELITY: COMPLIANT**
|
|
||||||
|
|
||||||
However, **code quality issues must be fixed** before final approval. The duplicate code blocks are merge conflicts or copy-paste errors that will cause:
|
|
||||||
- TypeScript compilation errors
|
|
||||||
- Runtime errors
|
|
||||||
- Incorrect behavior
|
|
||||||
|
|
||||||
### Recommended Actions
|
|
||||||
|
|
||||||
1. Remove duplicate imports in `i18n.ts`
|
|
||||||
2. Remove duplicate `resources` object definition in `i18n.ts`
|
|
||||||
3. Remove duplicate `handleLocaleChange` body in `Settings.tsx`
|
|
||||||
4. Remove duplicate `useStyles()` call in `App.tsx`
|
|
||||||
5. Remove duplicate useState declarations in `App.tsx`
|
|
||||||
6. Fix incomplete code block in `ipc-handlers.ts`
|
|
||||||
7. Consider making Ant Design locale dynamic in `main.tsx` (currently hardcoded)
|
|
||||||
@@ -1,857 +0,0 @@
|
|||||||
# Kintone Customize Manager - 核心功能实现计划
|
|
||||||
|
|
||||||
## TL;DR
|
|
||||||
|
|
||||||
> **Quick Summary**: 实现 Kintone Customize Manager 的核心功能,包括多 Domain 管理、资源浏览、拖拽部署和版本管理。
|
|
||||||
>
|
|
||||||
> **Deliverables**:
|
|
||||||
> - 多 Domain 配置管理(创建/编辑/删除/切换)
|
|
||||||
> - Space 和 App 浏览树
|
|
||||||
> - 拖拽文件部署到 Kintone
|
|
||||||
> - 版本历史管理
|
|
||||||
> - Kintone API 封装
|
|
||||||
>
|
|
||||||
> **Estimated Effort**: Large
|
|
||||||
> **Parallel Execution**: YES - 6 waves
|
|
||||||
> **Critical Path**: 类型定义 → Store → API 封装 → Domain 管理 → App 详情 → 部署功能
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Context
|
|
||||||
|
|
||||||
### Original Request
|
|
||||||
按照 REQUIREMENTS.md 创建任务计划,实现 Kintone Customize Manager 桌面应用的核心功能。
|
|
||||||
|
|
||||||
### Interview Summary
|
|
||||||
**Key Discussions**:
|
|
||||||
- **项目状态**: 全新项目,已使用 electron-vite 脚手架初始化并引入依赖库
|
|
||||||
- **优先级**: 核心功能优先(Domain 管理 + 部署)
|
|
||||||
- **测试策略**: 仅 QA 验证(不需要单元测试)
|
|
||||||
|
|
||||||
**Research Findings**:
|
|
||||||
- 项目已配置 electron-vite + electron-builder
|
|
||||||
- 已安装 LobeHub UI + Ant Design 6 + CodeMirror 6
|
|
||||||
- 主进程入口已创建(src/main/index.ts)
|
|
||||||
- 基础项目结构已建立
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Work Objectives
|
|
||||||
|
|
||||||
### Core Objective
|
|
||||||
实现 Kintone Customize Manager 的核心功能,让用户能够管理多个 Kintone 实例、浏览应用资源、拖拽部署自定义代码。
|
|
||||||
|
|
||||||
### Concrete Deliverables
|
|
||||||
- `src/main/kintone-api.ts` - Kintone REST API 封装
|
|
||||||
- `src/main/storage.ts` - 文件系统和密码存储
|
|
||||||
- `src/renderer/src/stores/domainStore.ts` - Domain 状态管理
|
|
||||||
- `src/renderer/src/components/DomainManager/` - Domain 管理 UI
|
|
||||||
- `src/renderer/src/components/SpaceTree/` - Space/App 浏览树
|
|
||||||
- `src/renderer/src/components/AppDetail/` - App 详情页
|
|
||||||
- `src/renderer/src/components/FileUploader/` - 拖拽部署组件
|
|
||||||
- `src/renderer/src/components/VersionHistory/` - 版本历史
|
|
||||||
|
|
||||||
### Definition of Done
|
|
||||||
- [ ] 可创建/编辑/删除 Domain 配置
|
|
||||||
- [ ] 可浏览 Space 和 App 列表
|
|
||||||
- [ ] 可拖拽文件部署到 Kintone
|
|
||||||
- [ ] 部署前自动备份当前版本
|
|
||||||
- [ ] 可查看版本历史
|
|
||||||
|
|
||||||
### Must Have
|
|
||||||
- 密码使用 safeStorage 加密存储
|
|
||||||
- 所有 Kintone API 调用有错误处理
|
|
||||||
- 部署前有确认 Dialog 和代码对比
|
|
||||||
|
|
||||||
### Must NOT Have (Guardrails)
|
|
||||||
- 不包含 Plugin 管理功能(P2 需求)
|
|
||||||
- 不包含批量操作功能(P1 需求)
|
|
||||||
- 不包含国际化(初始版本仅中文)
|
|
||||||
- 不实现单元测试(仅 QA 验证)
|
|
||||||
|
|
||||||
### Commit Policy (IMPORTANT)
|
|
||||||
**一个任务 = 一次提交**
|
|
||||||
|
|
||||||
- ✅ 每个任务完成后必须单独提交
|
|
||||||
- ✅ 提交信息格式:`type(scope): description`(约定式提交)
|
|
||||||
- ❌ 不要将多个任务合并到一次提交中
|
|
||||||
- ⚠️ 如果计划中标注 "groups with N",同 Wave 任务可合并提交
|
|
||||||
|
|
||||||
**提交类型**:`feat` | `fix` | `refactor` | `docs` | `style` | `test` | `chore`
|
|
||||||
|
|
||||||
**提交前检查清单**:
|
|
||||||
1. 完成该任务的所有 "What to do" 内容
|
|
||||||
2. 通过 `npx tsc --noEmit` 类型检查
|
|
||||||
3. 执行该任务的 QA Scenarios 并保存证据到 `.sisyphus/evidence/`
|
|
||||||
4. 代码格式化(`npm run format`)
|
|
||||||
- 不包含 Plugin 管理功能(P2 需求)
|
|
||||||
- 不包含批量操作功能(P1 需求)
|
|
||||||
- 不包含国际化(初始版本仅中文)
|
|
||||||
- 不实现单元测试(仅 QA 验证)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Verification Strategy
|
|
||||||
|
|
||||||
> **ZERO HUMAN INTERVENTION** — ALL verification is agent-executed. No exceptions.
|
|
||||||
|
|
||||||
### Test Decision
|
|
||||||
- **Infrastructure exists**: NO
|
|
||||||
- **Automated tests**: None
|
|
||||||
- **Framework**: None
|
|
||||||
- **Agent-Executed QA**: ALWAYS (mandatory for all tasks)
|
|
||||||
|
|
||||||
### QA Policy
|
|
||||||
Every task MUST include agent-executed QA scenarios. Evidence saved to `.sisyphus/evidence/task-{N}-{scenario-slug}.{ext}`.
|
|
||||||
|
|
||||||
- **Frontend/UI**: Use Playwright — Navigate, interact, assert DOM, screenshot
|
|
||||||
- **API/Backend**: Use Bash (curl) — Send requests, assert status + response fields
|
|
||||||
- **Main Process**: Use Bash (ts-node) — Run IPC handlers, verify responses
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Execution Strategy
|
|
||||||
|
|
||||||
### Parallel Execution Waves
|
|
||||||
|
|
||||||
```
|
|
||||||
Wave 1 (Start Immediately — foundation + types):
|
|
||||||
├── Task 1: 共享类型定义 [quick]
|
|
||||||
├── Task 2: 主进程存储模块 [quick]
|
|
||||||
├── Task 3: Kintone API 封装 [deep]
|
|
||||||
├── Task 4: IPC 通信处理 [quick]
|
|
||||||
├── Task 5: Preload API 暴露 [quick]
|
|
||||||
└── Task 6: Zustand Store 基础 [quick]
|
|
||||||
|
|
||||||
Wave 2 (After Wave 1 — Domain 管理):
|
|
||||||
├── Task 7: Domain Store 完整实现 [quick]
|
|
||||||
├── Task 8: DomainManager UI 组件 [visual-engineering]
|
|
||||||
├── Task 9: Domain 表单 Dialog [visual-engineering]
|
|
||||||
└── Task 10: Domain 列表连接 Store [quick]
|
|
||||||
|
|
||||||
Wave 3 (After Wave 2 — 资源浏览):
|
|
||||||
├── Task 11: SpaceTree 组件 [visual-engineering]
|
|
||||||
├── Task 12: App 列表渲染 [visual-engineering]
|
|
||||||
├── Task 13: App 详情页布局 [visual-engineering]
|
|
||||||
└── Task 14: 代码查看器组件 [visual-engineering]
|
|
||||||
|
|
||||||
Wave 4 (After Wave 3 — 部署功能):
|
|
||||||
├── Task 15: FileUploader 拖拽组件 [visual-engineering]
|
|
||||||
├── Task 16: 部署位置选择器 [visual-engineering]
|
|
||||||
├── Task 17: 代码 Diff 对比组件 [visual-engineering]
|
|
||||||
├── Task 18: 部署确认 Dialog [visual-engineering]
|
|
||||||
└── Task 19: 部署执行 IPC 处理 [deep]
|
|
||||||
|
|
||||||
Wave 5 (After Wave 4 — 版本管理):
|
|
||||||
├── Task 20: 版本历史存储逻辑 [quick]
|
|
||||||
├── Task 21: VersionHistory UI 组件 [visual-engineering]
|
|
||||||
├── Task 22: 版本对比功能 [visual-engineering]
|
|
||||||
└── Task 23: 版本回滚部署 [deep]
|
|
||||||
|
|
||||||
Wave 6 (After Wave 5 — 集成 + QA):
|
|
||||||
├── Task 24: App 页面集成 [deep]
|
|
||||||
├── Task 25: 端到端 Playwright QA [unspecified-high]
|
|
||||||
└── Task 26: Git 清理 + 标签 [git]
|
|
||||||
|
|
||||||
Critical Path: Task 1 → Task 6 → Task 7 → Task 10 → Task 11 → Task 13 → Task 15 → Task 19 → Task 24 → Task 25
|
|
||||||
Parallel Speedup: ~65% faster than sequential
|
|
||||||
Max Concurrent: 5-6 (Waves 1, 3, 4)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## TODOs
|
|
||||||
|
|
||||||
- [x] 1. 共享类型定义
|
|
||||||
|
|
||||||
**What to do**:
|
|
||||||
- 创建 `src/renderer/src/types/domain.ts` - Domain 配置类型
|
|
||||||
- 创建 `src/renderer/src/types/kintone.ts` - Kintone API 响应类型
|
|
||||||
- 创建 `src/renderer/src/types/version.ts` - 版本历史类型
|
|
||||||
- 创建 `src/renderer/src/types/ipc.ts` - IPC 通信类型
|
|
||||||
|
|
||||||
**Must NOT do**:
|
|
||||||
- 不要包含业务逻辑(仅类型定义)
|
|
||||||
- 不要使用 `any` 类型
|
|
||||||
|
|
||||||
**Recommended Agent Profile**:
|
|
||||||
- **Category**: `quick`
|
|
||||||
- **Skills**: []
|
|
||||||
- **Reason**: 简单的类型定义文件,无复杂逻辑
|
|
||||||
|
|
||||||
**Parallelization**:
|
|
||||||
- **Can Run In Parallel**: YES
|
|
||||||
- **Parallel Group**: Wave 1 (with Tasks 2-6)
|
|
||||||
- **Blocks**: Tasks 3, 7, 11, 20
|
|
||||||
- **Blocked By**: None
|
|
||||||
|
|
||||||
**References**:
|
|
||||||
- `REQUIREMENTS.md:272-284` - Domain 数据结构
|
|
||||||
- `REQUIREMENTS.md:405-437` - Download/Version 数据结构
|
|
||||||
- `REQUIREMENTS.md:527-545` - Deploy 数据结构
|
|
||||||
|
|
||||||
**Acceptance Criteria**:
|
|
||||||
- [ ] `src/renderer/src/types/domain.ts` 包含 Domain 接口
|
|
||||||
- [ ] `src/renderer/src/types/kintone.ts` 包含 Kintone API 响应类型
|
|
||||||
- [ ] `src/renderer/src/types/version.ts` 包含 Version 接口
|
|
||||||
- [ ] `src/renderer/src/types/ipc.ts` 包含 IPC 请求/响应类型
|
|
||||||
|
|
||||||
**QA Scenarios**:
|
|
||||||
```
|
|
||||||
Scenario: 类型定义编译检查
|
|
||||||
Tool: Bash (tsc)
|
|
||||||
Preconditions: 项目根目录
|
|
||||||
Steps:
|
|
||||||
1. 运行 `npx tsc --noEmit`
|
|
||||||
2. 验证输出无错误
|
|
||||||
Expected Result: 编译通过,无类型错误
|
|
||||||
Evidence: .sisyphus/evidence/task-1-types-check.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
**Commit**: YES (groups with 2-6)
|
|
||||||
- Message: `feat(types): add shared TypeScript type definitions`
|
|
||||||
- Files: `src/renderer/src/types/*.ts`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
- [x] 2. 主进程存储模块
|
|
||||||
|
|
||||||
**What to do**:
|
|
||||||
- 创建 `src/main/storage.ts` - 文件系统操作
|
|
||||||
- 实现 safeStorage 加密存储密码
|
|
||||||
- 实现 Domain 配置的读取/保存
|
|
||||||
- 实现版本历史的存储逻辑
|
|
||||||
- 实现下载文件的存储逻辑
|
|
||||||
|
|
||||||
**Must NOT do**:
|
|
||||||
- 不要硬编码路径(使用 electron-store)
|
|
||||||
- 不要明文存储密码
|
|
||||||
|
|
||||||
**Recommended Agent Profile**:
|
|
||||||
- **Category**: `quick`
|
|
||||||
- **Skills**: []
|
|
||||||
- **Reason**: 主进程工具模块,无 UI 交互
|
|
||||||
|
|
||||||
**Parallelization**:
|
|
||||||
- **Can Run In Parallel**: YES
|
|
||||||
- **Parallel Group**: Wave 1 (with Tasks 1, 3-6)
|
|
||||||
- **Blocks**: Tasks 3, 7, 20
|
|
||||||
- **Blocked By**: None
|
|
||||||
|
|
||||||
**References**:
|
|
||||||
- `REQUIREMENTS.md:125-145` - safeStorage 使用示例
|
|
||||||
- `REQUIREMENTS.md:197-214` - 本地存储结构
|
|
||||||
- `package.json:31` - electron-store 依赖
|
|
||||||
|
|
||||||
**Acceptance Criteria**:
|
|
||||||
- [ ] `src/main/storage.ts` 包含 saveDomain/getDomain/deleteDomain 函数
|
|
||||||
- [ ] 密码使用 safeStorage 加密
|
|
||||||
- [ ] 配置文件保存在 `~/.kintone-manager/config.json`
|
|
||||||
- [ ] Linux 环境检测 safeStorage 后端
|
|
||||||
|
|
||||||
**QA Scenarios**:
|
|
||||||
```
|
|
||||||
Scenario: 存储模块功能验证
|
|
||||||
Tool: Bash (ts-node)
|
|
||||||
Preconditions: 主进程环境
|
|
||||||
Steps:
|
|
||||||
1. 编写测试脚本调用 saveDomain
|
|
||||||
2. 调用 getDomain 验证读取
|
|
||||||
3. 调用 deleteDomain 验证删除
|
|
||||||
Expected Result: CRUD 操作均成功,返回预期结果
|
|
||||||
Evidence: .sisyphus/evidence/task-2-storage-test.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
**Commit**: YES (groups with 1, 3-6)
|
|
||||||
- Message: `feat(main): implement storage module with safeStorage`
|
|
||||||
- Files: `src/main/storage.ts`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
- [x] 3. Kintone API 封装
|
|
||||||
|
|
||||||
**What to do**:
|
|
||||||
- 创建 `src/main/kintone-api.ts` - Kintone REST API 客户端
|
|
||||||
- 实现认证(密码认证 + API Token)
|
|
||||||
- 实现 Space 列表获取
|
|
||||||
- 实现 App 列表获取
|
|
||||||
- 实现 App 配置获取
|
|
||||||
- 实现文件上传/下载
|
|
||||||
- 实现应用配置更新(部署)
|
|
||||||
|
|
||||||
**Must NOT do**:
|
|
||||||
- 不要包含 UI 逻辑
|
|
||||||
- 不要硬编码域名和凭证
|
|
||||||
|
|
||||||
**Recommended Agent Profile**:
|
|
||||||
- **Category**: `deep`
|
|
||||||
- **Skills**: []
|
|
||||||
- **Reason**: 核心业务逻辑,需要处理认证、错误重试、文件流
|
|
||||||
|
|
||||||
**Parallelization**:
|
|
||||||
- **Can Run In Parallel**: YES
|
|
||||||
- **Parallel Group**: Wave 1 (with Tasks 1, 2, 4-6)
|
|
||||||
- **Blocks**: Tasks 11, 12, 19
|
|
||||||
- **Blocked By**: Task 1 (types), Task 2 (storage)
|
|
||||||
|
|
||||||
**References**:
|
|
||||||
- `REQUIREMENTS.md:331-345` - Kintone API 端点
|
|
||||||
- `REQUIREMENTS.md:502-522` - 部署 API 端点
|
|
||||||
- `REQUIREMENTS.md:77-88` - 密码认证 vs API Token
|
|
||||||
|
|
||||||
**Acceptance Criteria**:
|
|
||||||
- [ ] `src/main/kintone-api.ts` 包含 KintoneClient 类
|
|
||||||
- [ ] 支持密码认证和 API Token 认证
|
|
||||||
- [ ] 实现 getSpaces/getApps/getAppConfig 方法
|
|
||||||
- [ ] 实现 uploadFile/downloadFile方法
|
|
||||||
- [ ] 实现 updateAppConfig 方法(部署)
|
|
||||||
- [ ] 所有方法有错误处理和超时控制(30 秒)
|
|
||||||
|
|
||||||
**QA Scenarios**:
|
|
||||||
```
|
|
||||||
Scenario: Kintone API 连接测试
|
|
||||||
Tool: Bash (ts-node)
|
|
||||||
Preconditions: 有效的 Kintone 凭证
|
|
||||||
Steps:
|
|
||||||
1. 创建 KintoneClient 实例
|
|
||||||
2. 调用 getSpaces() 获取 Space 列表
|
|
||||||
3. 调用 getApps(spaceId) 获取 App 列表
|
|
||||||
Expected Result: 成功返回 Space 和 App 列表,无错误
|
|
||||||
Evidence: .sisyphus/evidence/task-3-api-test.txt
|
|
||||||
|
|
||||||
Scenario: 错误处理验证
|
|
||||||
Tool: Bash (ts-node)
|
|
||||||
Preconditions: 无效的 Kintone 凭证
|
|
||||||
Steps:
|
|
||||||
1. 创建 KintoneClient 实例(错误凭证)
|
|
||||||
2. 调用 getSpaces()
|
|
||||||
Expected Result: 抛出认证错误,错误信息清晰
|
|
||||||
Evidence: .sisyphus/evidence/task-3-api-error.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
**Commit**: YES (groups with 1, 2, 4-6)
|
|
||||||
- Message: `feat(main): implement Kintone REST API client`
|
|
||||||
- Files: `src/main/kintone-api.ts`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
- [x] 4. IPC 通信处理
|
|
||||||
|
|
||||||
**What to do**:
|
|
||||||
- 创建 `src/main/ipc-handlers.ts` - IPC 请求处理
|
|
||||||
- 实现 Domain 管理的 IPC 处理(create/update/delete/list)
|
|
||||||
- 实现资源浏览的 IPC 处理(getSpaces/getApps/getAppConfig)
|
|
||||||
- 实现部署的 IPC 处理(deploy/download)
|
|
||||||
- 实现版本管理的 IPC 处理(getVersions/rollback)
|
|
||||||
|
|
||||||
**Must NOT do**:
|
|
||||||
- 不要包含业务逻辑(调用 kintone-api 和 storage)
|
|
||||||
- 不要直接操作 DOM 或 UI
|
|
||||||
|
|
||||||
**Recommended Agent Profile**:
|
|
||||||
- **Category**: `quick`
|
|
||||||
- **Skills**: []
|
|
||||||
- **Reason**: 简单的 IPC 路由和错误处理
|
|
||||||
|
|
||||||
**Parallelization**:
|
|
||||||
- **Can Run In Parallel**: YES
|
|
||||||
- **Parallel Group**: Wave 1 (with Tasks 1-3, 5-6)
|
|
||||||
- **Blocks**: Tasks 7-10, 19
|
|
||||||
- **Blocked By**: Task 2 (storage), Task 3 (kintone-api)
|
|
||||||
|
|
||||||
**References**:
|
|
||||||
- `src/main/index.ts:58` - 现有 IPC 示例
|
|
||||||
- `REQUIREMENTS.md:228-268` - Domain 管理功能需求
|
|
||||||
|
|
||||||
**Acceptance Criteria**:
|
|
||||||
- [ ] `src/main/ipc-handlers.ts` 包含所有 Domain 管理 handler
|
|
||||||
- [ ] 包含所有资源浏览 handler
|
|
||||||
- [ ] 包含部署和下载 handler
|
|
||||||
- [ ] 包含版本管理 handler
|
|
||||||
- [ ] 所有 handler 返回统一格式:`{ success: boolean, data?: T, error?: string }`
|
|
||||||
|
|
||||||
**QA Scenarios**:
|
|
||||||
```
|
|
||||||
Scenario: IPC handler 调用测试
|
|
||||||
Tool: Bash (ts-node)
|
|
||||||
Preconditions: 主进程运行中
|
|
||||||
Steps:
|
|
||||||
1. 使用 ipcMain.invoke 调用 handler
|
|
||||||
2. 验证返回格式符合约定
|
|
||||||
Expected Result: 所有 handler 返回成功,格式正确
|
|
||||||
Evidence: .sisyphus/evidence/task-4-ipc-test.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
**Commit**: YES (groups with 1-3, 5-6)
|
|
||||||
- Message: `feat(main): implement IPC handlers for all features`
|
|
||||||
- Files: `src/main/ipc-handlers.ts`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
- [x] 5. Preload API 暴露
|
|
||||||
|
|
||||||
**What to do**:
|
|
||||||
- 更新 `src/preload/index.ts` - 暴露 API 到渲染进程
|
|
||||||
- 定义 `src/preload/index.d.ts` - TypeScript 类型
|
|
||||||
- 使用 contextBridge 暴露安全的 API
|
|
||||||
- 包含所有 IPC 调用的封装
|
|
||||||
|
|
||||||
**Must NOT do**:
|
|
||||||
- 不要暴露完整的 ipcRenderer(不安全)
|
|
||||||
- 不要包含业务逻辑
|
|
||||||
|
|
||||||
**Recommended Agent Profile**:
|
|
||||||
- **Category**: `quick`
|
|
||||||
- **Skills**: []
|
|
||||||
- **Reason**: 标准的 Electron preload 模式
|
|
||||||
|
|
||||||
**Parallelization**:
|
|
||||||
- **Can Run In Parallel**: YES
|
|
||||||
- **Parallel Group**: Wave 1 (with Tasks 1-4, 6)
|
|
||||||
- **Blocks**: Tasks 7-26 (all renderer tasks)
|
|
||||||
- **Blocked By**: Task 4 (ipc-handlers)
|
|
||||||
|
|
||||||
**References**:
|
|
||||||
- `src/preload/index.ts` - 现有 preload 脚本
|
|
||||||
- `src/preload/index.d.ts` - 现有类型定义
|
|
||||||
- `AGENTS.md:IPC 通信规范` - IPC 通信规范
|
|
||||||
|
|
||||||
**Acceptance Criteria**:
|
|
||||||
- [ ] `src/preload/index.ts` 暴露 window.api 对象
|
|
||||||
- [ ] `src/preload/index.d.ts` 定义 ElectronAPI 接口
|
|
||||||
- [ ] 包含所有 Domain 管理 API
|
|
||||||
- [ ] 包含所有资源浏览 API
|
|
||||||
- [ ] 包含所有部署和版本管理 API
|
|
||||||
- [ ] contextIsolation 启用
|
|
||||||
|
|
||||||
**QA Scenarios**:
|
|
||||||
```
|
|
||||||
Scenario: Preload API 可用性检查
|
|
||||||
Tool: Bash (Playwright)
|
|
||||||
Preconditions: 应用启动
|
|
||||||
Steps:
|
|
||||||
1. 打开开发者工具
|
|
||||||
2. 在 Console 中执行 `typeof window.api`
|
|
||||||
Expected Result: 返回 'object',API 对象存在
|
|
||||||
Evidence: .sisyphus/evidence/task-5-preload-check.png
|
|
||||||
```
|
|
||||||
|
|
||||||
**Commit**: YES (groups with 1-4, 6)
|
|
||||||
- Message: `feat(preload): expose IPC APIs via contextBridge`
|
|
||||||
- Files: `src/preload/index.ts`, `src/preload/index.d.ts`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
- [x] 6. Zustand Store 基础架构
|
|
||||||
|
|
||||||
**What to do**:
|
|
||||||
- 创建 `src/renderer/src/stores/domainStore.ts` - Domain 状态
|
|
||||||
- 创建 `src/renderer/src/stores/appStore.ts` - App 浏览状态
|
|
||||||
- 创建 `src/renderer/src/stores/deployStore.ts` - 部署状态
|
|
||||||
- 创建 `src/renderer/src/stores/versionStore.ts` - 版本历史状态
|
|
||||||
- 使用 persist 中间件持久化
|
|
||||||
|
|
||||||
**Must NOT do**:
|
|
||||||
- 不要包含 UI 逻辑
|
|
||||||
- 不要直接调用 IPC(在 actions 中调用)
|
|
||||||
|
|
||||||
**Recommended Agent Profile**:
|
|
||||||
- **Category**: `quick`
|
|
||||||
- **Skills**: []
|
|
||||||
- **Reason**: 标准 Zustand 模式
|
|
||||||
|
|
||||||
**Parallelization**:
|
|
||||||
- **Can Run In Parallel**: YES
|
|
||||||
- **Parallel Group**: Wave 1 (with Tasks 1-5)
|
|
||||||
- **Blocks**: Tasks 7-26 (all UI components)
|
|
||||||
- **Blocked By**: Task 1 (types), Task 5 (preload API)
|
|
||||||
|
|
||||||
**References**:
|
|
||||||
- `AGENTS.md:Zustand Store 规范` - Zustand 规范
|
|
||||||
- `package.json:37` - zustand 依赖
|
|
||||||
- `REQUIREMENTS.md:269-284` - Domain 数据结构
|
|
||||||
|
|
||||||
**Acceptance Criteria**:
|
|
||||||
- [ ] `domainStore.ts` 包含 domains/currentDomain/actions
|
|
||||||
- [ ] `appStore.ts` 包含 spaces/apps/currentApp
|
|
||||||
- [ ] `deployStore.ts` 包含 deployParams/status
|
|
||||||
- [ ] `versionStore.ts` 包含 versions/currentVersion
|
|
||||||
- [ ] 所有 store 使用 persist 中间件
|
|
||||||
- [ ] TypeScript 类型完整
|
|
||||||
|
|
||||||
**QA Scenarios**:
|
|
||||||
```
|
|
||||||
Scenario: Store 基础功能验证
|
|
||||||
Tool: Bash (Playwright)
|
|
||||||
Preconditions: 应用启动
|
|
||||||
Steps:
|
|
||||||
1. 打开开发者工具 Console
|
|
||||||
2. 验证 store 存在并可访问
|
|
||||||
Expected Result: 所有 store 可访问,无错误
|
|
||||||
Evidence: .sisyphus/evidence/task-6-store-check.png
|
|
||||||
```
|
|
||||||
|
|
||||||
**Commit**: YES (groups with 1-5)
|
|
||||||
- Message: `feat(renderer): setup Zustand stores for all features`
|
|
||||||
- Files: `src/renderer/src/stores/*.ts`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
- [x] 7. Domain Store 完整实现
|
|
||||||
|
|
||||||
**What to do**:
|
|
||||||
- 完善 `domainStore.ts` - 添加 IPC 调用
|
|
||||||
- 实现 loadDomains - 加载所有 Domain
|
|
||||||
- 实现 addDomain - 添加新 Domain
|
|
||||||
- 实现 updateDomain - 更新 Domain
|
|
||||||
- 实现 deleteDomain - 删除 Domain
|
|
||||||
- 实现 setCurrentDomain - 切换 Domain
|
|
||||||
- 实现 testConnection - 测试连接
|
|
||||||
|
|
||||||
**Must NOT do**:
|
|
||||||
- 不要包含 UI 逻辑
|
|
||||||
- 不要硬编码错误处理
|
|
||||||
|
|
||||||
**Recommended Agent Profile**:
|
|
||||||
- **Category**: `quick`
|
|
||||||
- **Skills**: []
|
|
||||||
- **Reason**: Store 逻辑扩展
|
|
||||||
|
|
||||||
**Parallelization**:
|
|
||||||
- **Can Run In Parallel**: YES
|
|
||||||
- **Parallel Group**: Wave 2 (with Tasks 8-10)
|
|
||||||
- **Blocks**: Tasks 8-10 (Domain UI)
|
|
||||||
- **Blocked By**: Task 6 (store基础), Task 5 (preload API)
|
|
||||||
|
|
||||||
**References**:
|
|
||||||
- `src/renderer/src/stores/domainStore.ts` - 基础 store
|
|
||||||
- `REQUIREMENTS.md:228-268` - Domain 管理功能
|
|
||||||
|
|
||||||
**Acceptance Criteria**:
|
|
||||||
- [ ] 所有 actions 调用 window.api
|
|
||||||
- [ ] 错误处理完善
|
|
||||||
- [ ] 状态更新正确
|
|
||||||
- [ ] 连接状态检测实现
|
|
||||||
|
|
||||||
**QA Scenarios**:
|
|
||||||
```
|
|
||||||
Scenario: Domain CRUD 操作
|
|
||||||
Tool: Bash (Playwright)
|
|
||||||
Preconditions: 应用启动
|
|
||||||
Steps:
|
|
||||||
1. 调用 addDomain 添加测试 Domain
|
|
||||||
2. 调用 loadDomains 验证已添加
|
|
||||||
3. 调用 updateDomain 更新信息
|
|
||||||
4. 调用 deleteDomain 删除
|
|
||||||
Expected Result: 所有操作成功,状态正确更新
|
|
||||||
Evidence: .sisyphus/evidence/task-7-domain-crud.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
**Commit**: YES
|
|
||||||
- Message: `feat(store): implement domain store actions with IPC`
|
|
||||||
- Files: `src/renderer/src/stores/domainStore.ts`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
- [x] 8. DomainManager UI 组件
|
|
||||||
|
|
||||||
**What to do**:
|
|
||||||
- 创建 `src/renderer/src/components/DomainManager/DomainManager.tsx`
|
|
||||||
- 创建 `src/renderer/src/components/DomainManager/DomainList.tsx`
|
|
||||||
- 创建 `src/renderer/src/components/DomainManager/DomainItem.tsx`
|
|
||||||
- 使用 LobeHub UI + Ant Design 组件
|
|
||||||
- 显示 Domain 列表和连接状态
|
|
||||||
|
|
||||||
**Must NOT do**:
|
|
||||||
- 不要包含业务逻辑(使用 store)
|
|
||||||
- 不要直接调用 IPC
|
|
||||||
|
|
||||||
**Recommended Agent Profile**:
|
|
||||||
- **Category**: `visual-engineering`
|
|
||||||
- **Skills**: []
|
|
||||||
- **Reason**: UI 组件开发,需要设计布局
|
|
||||||
|
|
||||||
**Parallelization**:
|
|
||||||
- **Can Run In Parallel**: YES
|
|
||||||
- **Parallel Group**: Wave 2 (with Tasks 7, 9-10)
|
|
||||||
- **Blocks**: Tasks 10 (连接 Store)
|
|
||||||
- **Blocked By**: Task 7 (domain store)
|
|
||||||
|
|
||||||
**References**:
|
|
||||||
- `AGENTS.md:UI 组件规范` - LobeHub UI + antd-style
|
|
||||||
- `src/renderer/src/App.tsx` - 现有组件示例
|
|
||||||
- `package.json:27-30` - LobeHub UI + Ant Design
|
|
||||||
|
|
||||||
**Acceptance Criteria**:
|
|
||||||
- [ ] DomainManager 组件包含 Domain 列表
|
|
||||||
- [ ] DomainItem 显示名称、域名、连接状态
|
|
||||||
- [ ] 使用 antd-style 样式
|
|
||||||
- [ ] 支持暗黑模式
|
|
||||||
- [ ] 响应式布局
|
|
||||||
|
|
||||||
**QA Scenarios**:
|
|
||||||
```
|
|
||||||
Scenario: DomainManager 渲染检查
|
|
||||||
Tool: Playwright
|
|
||||||
Preconditions: 应用启动,有测试 Domain
|
|
||||||
Steps:
|
|
||||||
1. 导航到 DomainManager 页面
|
|
||||||
2. 验证 Domain 列表渲染
|
|
||||||
3. 验证连接状态图标显示
|
|
||||||
Expected Result: Domain 列表正确显示,样式正确
|
|
||||||
Evidence: .sisyphus/evidence/task-8-domain-manager-render.png
|
|
||||||
```
|
|
||||||
|
|
||||||
**Commit**: YES
|
|
||||||
- Message: `feat(ui): create DomainManager components`
|
|
||||||
- Files: `src/renderer/src/components/DomainManager/*.tsx`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
- [x] 9. Domain 表单 Dialog
|
|
||||||
|
|
||||||
**What to do**:
|
|
||||||
- 创建 `src/renderer/src/components/DomainManager/DomainForm.tsx`
|
|
||||||
- 实现创建 Domain 表单
|
|
||||||
- 实现编辑 Domain 表单
|
|
||||||
- 使用 Ant Design Form + Modal
|
|
||||||
- 表单验证(必填字段、格式检查)
|
|
||||||
|
|
||||||
**Must NOT do**:
|
|
||||||
- 不要包含业务逻辑(提交调用 store)
|
|
||||||
- 不要硬编码验证规则
|
|
||||||
|
|
||||||
**Recommended Agent Profile**:
|
|
||||||
- **Category**: `visual-engineering`
|
|
||||||
- **Skills**: []
|
|
||||||
- **Reason**: 表单 UI 组件
|
|
||||||
|
|
||||||
**Parallelization**:
|
|
||||||
- **Can Run In Parallel**: YES
|
|
||||||
- **Parallel Group**: Wave 2 (with Tasks 7-8, 10)
|
|
||||||
- **Blocks**: Tasks 10 (表单使用)
|
|
||||||
- **Blocked By**: Task 7 (domain store)
|
|
||||||
|
|
||||||
**References**:
|
|
||||||
- `REQUIREMENTS.md:228-247` - Domain 创建/编辑需求
|
|
||||||
- `AGENTS.md:UI 组件规范` - Ant Design 使用
|
|
||||||
|
|
||||||
**Acceptance Criteria**:
|
|
||||||
- [ ] DomainForm 组件支持创建和编辑模式
|
|
||||||
- [ ] 必填字段验证(名称、域名、用户名、密码)
|
|
||||||
- [ ] 认证类型切换(密码/API Token)
|
|
||||||
- [ ] API Token 字段条件显示
|
|
||||||
- [ ] 提交成功关闭 Dialog
|
|
||||||
|
|
||||||
**QA Scenarios**:
|
|
||||||
```
|
|
||||||
Scenario: 创建 Domain 表单
|
|
||||||
Tool: Playwright
|
|
||||||
Preconditions: 应用启动
|
|
||||||
Steps:
|
|
||||||
1. 点击"添加 Domain"按钮
|
|
||||||
2. 填写表单所有字段
|
|
||||||
3. 提交表单
|
|
||||||
4. 验证成功提示和 Dialog 关闭
|
|
||||||
Expected Result: 表单提交成功,Domain 添加到列表
|
|
||||||
Evidence: .sisyphus/evidence/task-9-domain-form-create.png
|
|
||||||
|
|
||||||
Scenario: 表单验证
|
|
||||||
Tool: Playwright
|
|
||||||
Preconditions: 打开创建 Domain Dialog
|
|
||||||
Steps:
|
|
||||||
1. 不填写任何字段,点击提交
|
|
||||||
2. 验证错误提示显示
|
|
||||||
Expected Result: 显示必填字段错误提示
|
|
||||||
Evidence: .sisyphus/evidence/task-9-domain-form-validation.png
|
|
||||||
```
|
|
||||||
|
|
||||||
**Commit**: YES
|
|
||||||
- Message: `feat(ui): create DomainForm dialog component`
|
|
||||||
- Files: `src/renderer/src/components/DomainManager/DomainForm.tsx`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
- [x] 10. Domain 列表连接 Store
|
|
||||||
|
|
||||||
**What to do**:
|
|
||||||
- 更新 `DomainManager.tsx` - 连接 Domain Store
|
|
||||||
- 使用 useDomainStore 获取状态
|
|
||||||
- 实现添加/编辑/删除按钮事件
|
|
||||||
- 实现 Domain 切换功能
|
|
||||||
- 实现连接状态检测
|
|
||||||
|
|
||||||
**Must NOT do**:
|
|
||||||
- 不要创建新的 store
|
|
||||||
- 不要直接调用 IPC
|
|
||||||
|
|
||||||
**Recommended Agent Profile**:
|
|
||||||
- **Category**: `quick`
|
|
||||||
- **Skills**: []
|
|
||||||
- **Reason**: 连接现有 store 和组件
|
|
||||||
|
|
||||||
**Parallelization**:
|
|
||||||
- **Can Run In Parallel**: NO
|
|
||||||
- **Parallel Group**: Sequential (after Tasks 7-9)
|
|
||||||
- **Blocks**: Tasks 11-26 (需要 Domain 切换)
|
|
||||||
- **Blocked By**: Tasks 7, 8, 9
|
|
||||||
|
|
||||||
**References**:
|
|
||||||
- `src/renderer/src/stores/domainStore.ts` - Domain Store
|
|
||||||
- `src/renderer/src/components/DomainManager/` - 现有组件
|
|
||||||
|
|
||||||
**Acceptance Criteria**:
|
|
||||||
- [ ] DomainManager 显示所有 Domain
|
|
||||||
- [ ] 点击 Domain 切换当前 Domain
|
|
||||||
- [ ] 添加按钮打开创建 Dialog
|
|
||||||
- [ ] 编辑按钮打开编辑 Dialog
|
|
||||||
- [ ] 删除按钮显示确认 Dialog
|
|
||||||
|
|
||||||
**QA Scenarios**:
|
|
||||||
```
|
|
||||||
Scenario: Domain 切换
|
|
||||||
Tool: Playwright
|
|
||||||
Preconditions: 有多个 Domain
|
|
||||||
Steps:
|
|
||||||
1. 点击 Domain A
|
|
||||||
2. 验证当前 Domain 状态更新
|
|
||||||
3. 验证连接状态检测触发
|
|
||||||
Expected Result: Domain 切换成功,状态更新
|
|
||||||
Evidence: .sisyphus/evidence/task-10-domain-switch.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
**Commit**: YES
|
|
||||||
- Message: `feat(ui): connect DomainManager to store`
|
|
||||||
- Files: `src/renderer/src/components/DomainManager/DomainManager.tsx`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
- [x] 11. SpaceTree 组件
|
|
||||||
|
|
||||||
**What to do**:
|
|
||||||
- 创建 `src/renderer/src/components/SpaceTree/SpaceTree.tsx`
|
|
||||||
- 创建 `src/renderer/src/components/SpaceTree/SpaceNode.tsx`
|
|
||||||
- 创建 `src/renderer/src/components/SpaceTree/AppNode.tsx`
|
|
||||||
- 使用 Ant Design Tree 组件
|
|
||||||
- 显示 Space 分组和 App 列表
|
|
||||||
- 支持搜索和过滤
|
|
||||||
|
|
||||||
**Must NOT do**:
|
|
||||||
- 不要包含业务逻辑(使用 appStore)
|
|
||||||
- 不要直接调用 IPC
|
|
||||||
|
|
||||||
**Recommended Agent Profile**:
|
|
||||||
- **Category**: `visual-engineering`
|
|
||||||
- **Skills**: []
|
|
||||||
- **Reason**: UI 树形组件开发
|
|
||||||
|
|
||||||
**Parallelization**:
|
|
||||||
- **Can Run In Parallel**: YES
|
|
||||||
- **Parallel Group**: Wave 3 (with Tasks 12-14)
|
|
||||||
- **Blocks**: Tasks 13-14 (App 详情)
|
|
||||||
- **Blocked By**: Task 10 (Domain 切换)
|
|
||||||
|
|
||||||
**References**:
|
|
||||||
- `REQUIREMENTS.md:296-330` - 资源浏览功能
|
|
||||||
- `AGENTS.md:UI 组件规范` - Ant Design Tree
|
|
||||||
|
|
||||||
**Acceptance Criteria**:
|
|
||||||
- [ ] SpaceTree 显示所有 Space
|
|
||||||
- [ ] 每个 Space 下显示 App 列表
|
|
||||||
- [ ] 支持展开/折叠 Space
|
|
||||||
- [ ] 点击 App 节点触发选择事件
|
|
||||||
- [ ] 支持按名称搜索 App
|
|
||||||
|
|
||||||
**QA Scenarios**:
|
|
||||||
```
|
|
||||||
Scenario: SpaceTree 渲染
|
|
||||||
Tool: Playwright
|
|
||||||
Preconditions: 已选择 Domain,有 Space 和 App
|
|
||||||
Steps:
|
|
||||||
1. 导航到资源浏览页面
|
|
||||||
2. 验证 Space 列表渲染
|
|
||||||
3. 展开 Space,验证 App 列表显示
|
|
||||||
Expected Result: Space 和 App 正确显示,树形结构完整
|
|
||||||
Evidence: .sisyphus/evidence/task-11-spacetree-render.png
|
|
||||||
|
|
||||||
Scenario: App 搜索
|
|
||||||
Tool: Playwright
|
|
||||||
Preconditions: SpaceTree 已加载
|
|
||||||
Steps:
|
|
||||||
1. 在搜索框输入 App 名称关键词
|
|
||||||
2. 验证过滤后的 App 列表
|
|
||||||
Expected Result: 只显示匹配的 App
|
|
||||||
Evidence: .sisyphus/evidence/task-11-spacetree-search.png
|
|
||||||
```
|
|
||||||
|
|
||||||
**Commit**: YES
|
|
||||||
- Message: `feat(ui): create SpaceTree component for browsing resources`
|
|
||||||
- Files: `src/renderer/src/components/SpaceTree/*.tsx`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
- [ ] 12-26. [待补充 - 由于输出限制,任务 12-26 将在后续会话中补充]
|
|
||||||
|
|
||||||
> **Note**: 受模型输出 token 限制,任务 12-26 的完整详情需要在执行过程中补充。
|
|
||||||
> 关键任务包括:
|
|
||||||
> - Task 12: App 列表渲染
|
|
||||||
> - Task 13: App 详情页布局
|
|
||||||
> - Task 14: 代码查看器组件
|
|
||||||
> - Task 15-19: 部署功能(FileUploader、位置选择、Diff 对比、确认 Dialog、部署执行)
|
|
||||||
> - Task 20-23: 版本管理(存储、UI、对比、回滚)
|
|
||||||
> - Task 24: App 页面集成
|
|
||||||
> - Task 25: 端到端 Playwright QA
|
|
||||||
> - Task 26: Git 清理 + 标签
|
|
||||||
|
|
||||||
**执行策略**: 按照 Execution Strategy 中的 Wave 3-6 逐步执行,每个任务的详细规格参考 REQUIREMENTS.md 对应章节。
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Final Verification Wave
|
|
||||||
|
|
||||||
> 4 review agents run in PARALLEL. ALL must APPROVE. Rejection → fix → re-run.
|
|
||||||
|
|
||||||
- [ ] F1. **Plan Compliance Audit** — `oracle`
|
|
||||||
Read the plan end-to-end. For each "Must Have": verify implementation exists (read file, curl endpoint, run command). For each "Must NOT Have": search codebase for forbidden patterns — reject with file:line if found. Check evidence files exist in .sisyphus/evidence/. Compare deliverables against plan.
|
|
||||||
Output: `Must Have [N/N] | Must NOT Have [N/N] | Tasks [N/N] | VERDICT: APPROVE/REJECT`
|
|
||||||
|
|
||||||
- [ ] F2. **Code Quality Review** — `unspecified-high`
|
|
||||||
Run `tsc --noEmit` + linter + `bun test`. Review all changed files for: `as any`/`@ts-ignore`, empty catches, console.log in prod, commented-out code, unused imports. Check AI slop: excessive comments, over-abstraction, generic names (data/result/item/temp).
|
|
||||||
Output: `Build [PASS/FAIL] | Lint [PASS/FAIL] | Tests [N pass/N fail] | Files [N clean/N issues] | VERDICT`
|
|
||||||
|
|
||||||
- [ ] F3. **Real Manual QA** — `unspecified-high` (+ `playwright` skill if UI)
|
|
||||||
Start from clean state. Execute EVERY QA scenario from EVERY task — follow exact steps, capture evidence. Test cross-task integration (features working together, not isolation). Test edge cases: empty state, invalid input, rapid actions. Save to `.sisyphus/evidence/final-qa/`.
|
|
||||||
Output: `Scenarios [N/N pass] | Integration [N/N] | Edge Cases [N tested] | VERDICT`
|
|
||||||
|
|
||||||
- [ ] F4. **Scope Fidelity Check** — `deep`
|
|
||||||
For each task: read "What to do", read actual diff (git log/diff). Verify 1:1 — everything in spec was built (no missing), nothing beyond spec was built (no creep). Check "Must NOT do" compliance. Detect cross-task contamination: Task N touching Task M's files. Flag unaccounted changes.
|
|
||||||
Output: `Tasks [N/N compliant] | Contamination [CLEAN/N issues] | Unaccounted [CLEAN/N files] | VERDICT`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Commit Strategy
|
|
||||||
|
|
||||||
- **Wave 1**: `feat(core): foundation modules` — types, storage, kintone-api, ipc, preload, stores
|
|
||||||
- **Wave 2**: `feat(domain): domain management` — domain store, DomainManager UI, DomainForm
|
|
||||||
- **Wave 3**: `feat(browse): resource browsing` — SpaceTree, AppList, AppDetail, CodeViewer
|
|
||||||
- **Wave 4**: `feat(deploy): drag-and-drop deployment` — FileUploader, position selector, diff view, deploy dialog
|
|
||||||
- **Wave 5**: `feat(version): version management` — version history, diff comparison, rollback
|
|
||||||
- **Wave 6**: `feat(integration): app integration + QA` — full app page, Playwright tests
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Success Criteria
|
|
||||||
|
|
||||||
### Verification Commands
|
|
||||||
```bash
|
|
||||||
npx tsc --noEmit # Expected: no errors
|
|
||||||
npm run dev # Expected: dev server starts successfully
|
|
||||||
npm run build # Expected: production build completes
|
|
||||||
```
|
|
||||||
|
|
||||||
### Final Checklist
|
|
||||||
- [ ] 所有"Must Have"功能实现
|
|
||||||
- [ ] 所有"Must NOT Have"功能未实现
|
|
||||||
- [ ] 所有编译通过(tsc --noEmit)
|
|
||||||
- [ ] 所有 QA 场景证据文件存在
|
|
||||||
- [ ] 应用可启动并运行
|
|
||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user