be370cc615
Project CI / AI game creator shell Rust shard 1/4 (push) Successful in 7m12s
Project CI / AI game creator shell Rust shard 2/4 (push) Successful in 7m17s
Project CI / AI game creator shell Rust shard 3/4 (push) Successful in 7m26s
Project CI / AI game creator shell Rust shard 4/4 (push) Successful in 7m37s
Project CI / AI game creator shell Rust smoke (push) Successful in 1m57s
Project CI / AI game creator shell Rust crates (push) Successful in 2m10s
Project CI / Frontend tests (push) Successful in 6m4s
Project CI / Native shell tests (push) Successful in 8m58s
Project CI / Backend tests (push) Has been cancelled
Project CI / AI game creator shell web tests (push) Has been cancelled
Project CI / Repository checks (push) Has been cancelled
- 新增设置「工作区」分类,承载「项目创建目录」的选择与恢复默认入口 - 自动建项命令新增可选 projectsRoot,未指定时沿用 AppData projects 默认目录 - 新增项目创建目录校验与解析:只接受目录选择器返回且通过私有路径门禁的既有目录 - 目录选择器新增可选 title 参数,用于「选择项目创建目录」文案 - 首页自动建项与模板建项在建项时携带用户选定的项目创建目录 - 客户端本地保存项目创建目录偏好,建项时重新校验,不作为授权凭据 - 补充设置页工作区、首页建项与目录偏好单测 - 修复项目开发视图缺失的 Shapes 图标导入,恢复 agc:typecheck 通过 - 同步实施计划、决策日志与排障记忆文档
82 lines
2.6 KiB
TypeScript
82 lines
2.6 KiB
TypeScript
import { useCallback, useRef, useState } from 'react';
|
|
|
|
import { resolveTauriInvoke } from '../../app/tauri';
|
|
import {
|
|
readProjectCreationDirectory,
|
|
writeProjectCreationDirectory,
|
|
} from './model';
|
|
|
|
/**
|
|
* 「项目创建目录」用户偏好。
|
|
*
|
|
* 默认沿用 AGC 管理的应用数据目录(`<app_data>/projects`);用户改选时必须走原生目录
|
|
* 选择器,因为只有它构成"用户显式选择"边界:选择结果当场按用户选择范围加固,后续建项
|
|
* 再由 Rust 侧私有路径门禁复核一次。
|
|
*/
|
|
export function useProjectCreationDirectory() {
|
|
const [projectCreationDirectory, setProjectCreationDirectory] = useState(
|
|
readProjectCreationDirectory,
|
|
);
|
|
const [projectCreationDirectoryBusy, setProjectCreationDirectoryBusy] =
|
|
useState(false);
|
|
const [projectCreationDirectoryStatus, setProjectCreationDirectoryStatus] =
|
|
useState('');
|
|
const pickInFlightRef = useRef(false);
|
|
|
|
const pickProjectCreationDirectory = useCallback(async () => {
|
|
if (pickInFlightRef.current) {
|
|
return;
|
|
}
|
|
const invoke = resolveTauriInvoke();
|
|
if (!invoke) {
|
|
setProjectCreationDirectoryStatus('需要在陶泥儿客户端内运行');
|
|
return;
|
|
}
|
|
pickInFlightRef.current = true;
|
|
setProjectCreationDirectoryBusy(true);
|
|
setProjectCreationDirectoryStatus('正在选择项目创建目录');
|
|
try {
|
|
const selected = await invoke<string | null>(
|
|
'pick_local_project_directory',
|
|
{
|
|
title: '选择项目创建目录',
|
|
...(projectCreationDirectory
|
|
? { initialPath: projectCreationDirectory }
|
|
: {}),
|
|
},
|
|
);
|
|
if (!selected) {
|
|
setProjectCreationDirectoryStatus('已取消');
|
|
return;
|
|
}
|
|
setProjectCreationDirectory(writeProjectCreationDirectory(selected));
|
|
setProjectCreationDirectoryStatus('已更新项目创建目录');
|
|
} catch (error) {
|
|
setProjectCreationDirectoryStatus(
|
|
error instanceof Error ? error.message : String(error),
|
|
);
|
|
} finally {
|
|
pickInFlightRef.current = false;
|
|
setProjectCreationDirectoryBusy(false);
|
|
}
|
|
}, [projectCreationDirectory]);
|
|
|
|
const resetProjectCreationDirectory = useCallback(() => {
|
|
writeProjectCreationDirectory('');
|
|
setProjectCreationDirectory('');
|
|
setProjectCreationDirectoryStatus('已恢复默认位置');
|
|
}, []);
|
|
|
|
return {
|
|
projectCreationDirectory,
|
|
projectCreationDirectoryBusy,
|
|
projectCreationDirectoryStatus,
|
|
pickProjectCreationDirectory,
|
|
resetProjectCreationDirectory,
|
|
};
|
|
}
|
|
|
|
export type ProjectCreationDirectoryController = ReturnType<
|
|
typeof useProjectCreationDirectory
|
|
>;
|