mirror of
https://github.com/LHY0125/PathEditor.git
synced 2026-06-29 18:15:55 +08:00
chore: 同步 v5.0 基础设施完善到 v5.1
从 v5.0 cherry-pick 的开源项目基础设施改进: 新增配置文件: - .editorconfig, .gitattributes, .prettierrc, .markdownlint.json - commitlint.config.js 新增 GitHub 社区文件: - .github/dependabot.yml — 依赖自动更新 - .github/CODEOWNERS — 自动 PR 审查分配 - .github/FUNDING.yml — 开源赞助入口 新增文档: - ROADMAP.md — 路线图 - SUPPORT.md — 帮助指南 - docs/screenshots/ — 应用截图 新增 Git Hooks: - .husky/pre-commit — lint-staged 自动格式化+修复 - .husky/commit-msg — commitlint 校验 CI 强化: - 新增 Prettier 格式检查 - 新增 Vitest 覆盖率 + Codecov 上报 - 保留 v5.1 已有的 rust-cache + jsdom 全局环境 修复: - index.html 标题 v4.0 → v5.1 - PathEditDialog set-state-in-effect 改用 useRef prevOpen 守卫 - merge-preview.test.tsx no-explicit-any 修复 - 所有 TS/TSX 文件 Prettier 格式化统一 v5.1 保留特性: - @tanstack/react-virtual 虚拟滚动 - jsdom 全局测试环境 - Swatinem/rust-cache CI 加速 - 105 测试全部通过
This commit is contained in:
@@ -3,7 +3,12 @@ import { useAppStore } from '@/store/app-store';
|
||||
import { TargetType } from '@/core/undo-redo';
|
||||
import { open } from '@tauri-apps/plugin-dialog';
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { importFromContent, exportToJson, exportToCsv, flattenImportResult } from '@/core/import-export';
|
||||
import {
|
||||
importFromContent,
|
||||
exportToJson,
|
||||
exportToCsv,
|
||||
flattenImportResult,
|
||||
} from '@/core/import-export';
|
||||
import type { PathEntry } from '@/core/path-entry';
|
||||
import { is_valid_path_format } from '@/core/validation';
|
||||
import { useKeyboard } from './use-keyboard';
|
||||
@@ -38,9 +43,10 @@ export function useAppActions(activeTab: TabId, dialogs: DialogState) {
|
||||
const idx = useAppStore.getState().selectedIndices[0];
|
||||
if (idx === undefined) return;
|
||||
const target = activeTab === 'user' ? TargetType.USER : TargetType.SYSTEM;
|
||||
const list = target === TargetType.SYSTEM
|
||||
? useAppStore.getState().sysPaths
|
||||
: useAppStore.getState().userPaths;
|
||||
const list =
|
||||
target === TargetType.SYSTEM
|
||||
? useAppStore.getState().sysPaths
|
||||
: useAppStore.getState().userPaths;
|
||||
const entry = list[idx];
|
||||
if (entry) setEditDialog({ open: true, index: idx, value: entry.path, target });
|
||||
}, [activeTab, setEditDialog]);
|
||||
@@ -71,14 +77,9 @@ export function useAppActions(activeTab: TabId, dialogs: DialogState) {
|
||||
}, [getCurrentTarget]);
|
||||
|
||||
const handleClean = useCallback(() => {
|
||||
const removed = useAppStore.getState().cleanPaths(
|
||||
getCurrentTarget(),
|
||||
is_valid_path_format,
|
||||
);
|
||||
const removed = useAppStore.getState().cleanPaths(getCurrentTarget(), is_valid_path_format);
|
||||
if (removed.length > 0) {
|
||||
useAppStore.getState().setStatusMessage(
|
||||
i18n.t('status.deleted', { count: removed.length }),
|
||||
);
|
||||
useAppStore.getState().setStatusMessage(i18n.t('status.deleted', { count: removed.length }));
|
||||
}
|
||||
}, [getCurrentTarget]);
|
||||
|
||||
@@ -95,9 +96,15 @@ export function useAppActions(activeTab: TabId, dialogs: DialogState) {
|
||||
if (result.system.length > 0 && result.user.length > 0) {
|
||||
setImportDialog({ open: true, system: result.system, user: result.user });
|
||||
} else if (result.system.length > 0) {
|
||||
useAppStore.getState().replacePaths(TargetType.SYSTEM, result.system.map(e => e.path));
|
||||
useAppStore.getState().replacePaths(
|
||||
TargetType.SYSTEM,
|
||||
result.system.map((e) => e.path),
|
||||
);
|
||||
} else if (result.user.length > 0) {
|
||||
useAppStore.getState().replacePaths(TargetType.USER, result.user.map(e => e.path));
|
||||
useAppStore.getState().replacePaths(
|
||||
TargetType.USER,
|
||||
result.user.map((e) => e.path),
|
||||
);
|
||||
}
|
||||
}, [setImportDialog]);
|
||||
|
||||
@@ -122,7 +129,10 @@ export function useAppActions(activeTab: TabId, dialogs: DialogState) {
|
||||
if (result.kind === 'warning') {
|
||||
// 长度超限,需要用户确认
|
||||
const { ask } = await import('@tauri-apps/plugin-dialog');
|
||||
const confirmed = await ask(i18n.t('status.saveWarningLongPaths'), { title: i18n.t('dialog.backupTitle'), kind: 'warning' });
|
||||
const confirmed = await ask(i18n.t('status.saveWarningLongPaths'), {
|
||||
title: i18n.t('dialog.backupTitle'),
|
||||
kind: 'warning',
|
||||
});
|
||||
if (confirmed) {
|
||||
await useAppStore.getState().savePaths(true);
|
||||
}
|
||||
@@ -156,33 +166,62 @@ export function useAppActions(activeTab: TabId, dialogs: DialogState) {
|
||||
|
||||
// ── 弹窗确认 ──
|
||||
|
||||
const handleNewConfirm = useCallback((value: string) => {
|
||||
setNewDialog(false);
|
||||
if (value.trim()) useAppStore.getState().addPath(value.trim(), getCurrentTarget());
|
||||
}, [getCurrentTarget, setNewDialog]);
|
||||
const handleNewConfirm = useCallback(
|
||||
(value: string) => {
|
||||
setNewDialog(false);
|
||||
if (value.trim()) useAppStore.getState().addPath(value.trim(), getCurrentTarget());
|
||||
},
|
||||
[getCurrentTarget, setNewDialog],
|
||||
);
|
||||
|
||||
const handleEditConfirm = useCallback((value: string) => {
|
||||
const d = dialogs.editDialog;
|
||||
setEditDialog({ open: false, index: -1, value: '', target: TargetType.SYSTEM });
|
||||
if (value.trim()) useAppStore.getState().editPath(d.index, value.trim(), d.target);
|
||||
}, [dialogs.editDialog, setEditDialog]);
|
||||
const handleEditConfirm = useCallback(
|
||||
(value: string) => {
|
||||
const d = dialogs.editDialog;
|
||||
setEditDialog({ open: false, index: -1, value: '', target: TargetType.SYSTEM });
|
||||
if (value.trim()) useAppStore.getState().editPath(d.index, value.trim(), d.target);
|
||||
},
|
||||
[dialogs.editDialog, setEditDialog],
|
||||
);
|
||||
|
||||
const handleImportSelect = useCallback((target: 'system' | 'user' | 'both') => {
|
||||
const { system, user } = dialogs.importDialog;
|
||||
const flat = flattenImportResult({ system, user }, target);
|
||||
if (target === 'both' && flat.system.length > 0 && flat.user.length > 0) {
|
||||
useAppStore.getState().replaceBothPaths(flat.system.map(e => e.path), flat.user.map(e => e.path));
|
||||
} else {
|
||||
if (flat.system.length > 0) useAppStore.getState().replacePaths(TargetType.SYSTEM, flat.system.map(e => e.path));
|
||||
if (flat.user.length > 0) useAppStore.getState().replacePaths(TargetType.USER, flat.user.map(e => e.path));
|
||||
}
|
||||
setImportDialog({ open: false, system: [], user: [] });
|
||||
}, [dialogs.importDialog, setImportDialog]);
|
||||
const handleImportSelect = useCallback(
|
||||
(target: 'system' | 'user' | 'both') => {
|
||||
const { system, user } = dialogs.importDialog;
|
||||
const flat = flattenImportResult({ system, user }, target);
|
||||
if (target === 'both' && flat.system.length > 0 && flat.user.length > 0) {
|
||||
useAppStore.getState().replaceBothPaths(
|
||||
flat.system.map((e) => e.path),
|
||||
flat.user.map((e) => e.path),
|
||||
);
|
||||
} else {
|
||||
if (flat.system.length > 0)
|
||||
useAppStore.getState().replacePaths(
|
||||
TargetType.SYSTEM,
|
||||
flat.system.map((e) => e.path),
|
||||
);
|
||||
if (flat.user.length > 0)
|
||||
useAppStore.getState().replacePaths(
|
||||
TargetType.USER,
|
||||
flat.user.map((e) => e.path),
|
||||
);
|
||||
}
|
||||
setImportDialog({ open: false, system: [], user: [] });
|
||||
},
|
||||
[dialogs.importDialog, setImportDialog],
|
||||
);
|
||||
|
||||
return {
|
||||
handleNew, handleEdit, handleBrowse, handleDelete,
|
||||
handleMoveUp, handleMoveDown, handleClean,
|
||||
handleImport, handleExport, handleSave,
|
||||
handleNewConfirm, handleEditConfirm, handleImportSelect,
|
||||
handleNew,
|
||||
handleEdit,
|
||||
handleBrowse,
|
||||
handleDelete,
|
||||
handleMoveUp,
|
||||
handleMoveDown,
|
||||
handleClean,
|
||||
handleImport,
|
||||
handleExport,
|
||||
handleSave,
|
||||
handleNewConfirm,
|
||||
handleEditConfirm,
|
||||
handleImportSelect,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user