feat: 添加文件描述编辑功能,支持标题、标签、摘要、描述和链接管理
This commit is contained in:
179
src/components/FileDescriptionDialog.tsx
Normal file
179
src/components/FileDescriptionDialog.tsx
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import { queryApi as projectApi } from '@/modules/project-api';
|
||||||
|
import { toast } from 'sonner';
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
DialogFooter,
|
||||||
|
} from '@/components/ui/dialog';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
import { Textarea } from '@/components/ui/textarea';
|
||||||
|
import { Input } from '@/components/ui/input';
|
||||||
|
import { Label } from '@/components/ui/label';
|
||||||
|
|
||||||
|
const API_URL = '/root/v1/dev-cnb';
|
||||||
|
|
||||||
|
export type FileDescriptionData = {
|
||||||
|
filepath: string;
|
||||||
|
title?: string;
|
||||||
|
tags?: string[];
|
||||||
|
summary?: string;
|
||||||
|
description?: string;
|
||||||
|
link?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface FileDescriptionDialogProps {
|
||||||
|
open: boolean;
|
||||||
|
onOpenChange: (open: boolean) => void;
|
||||||
|
data: FileDescriptionData;
|
||||||
|
onSuccess?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function FileDescriptionDialog({
|
||||||
|
open,
|
||||||
|
onOpenChange,
|
||||||
|
data,
|
||||||
|
onSuccess,
|
||||||
|
}: FileDescriptionDialogProps) {
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [formData, setFormData] = useState<FileDescriptionData>({
|
||||||
|
filepath: data.filepath,
|
||||||
|
title: '',
|
||||||
|
tags: [],
|
||||||
|
summary: '',
|
||||||
|
description: '',
|
||||||
|
link: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
// 当打开对话框或数据变化时,同步数据
|
||||||
|
useEffect(() => {
|
||||||
|
if (open && data.filepath) {
|
||||||
|
setFormData({
|
||||||
|
filepath: data.filepath,
|
||||||
|
title: data.title || '',
|
||||||
|
tags: data.tags || [],
|
||||||
|
summary: data.summary || '',
|
||||||
|
description: data.description || '',
|
||||||
|
link: data.link || '',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [open, data]);
|
||||||
|
|
||||||
|
const handleSave = async () => {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
// 过滤掉空值
|
||||||
|
const updateData: Partial<FileDescriptionData> = {
|
||||||
|
filepath: formData.filepath,
|
||||||
|
};
|
||||||
|
if (formData.title) updateData.title = formData.title;
|
||||||
|
if (formData.tags && formData.tags.length > 0) updateData.tags = formData.tags;
|
||||||
|
if (formData.summary) updateData.summary = formData.summary;
|
||||||
|
if (formData.description) updateData.description = formData.description;
|
||||||
|
if (formData.link) updateData.link = formData.link;
|
||||||
|
|
||||||
|
const res = await projectApi['project-file']['update'](updateData, { url: API_URL });
|
||||||
|
if (res.code === 200) {
|
||||||
|
toast.success('保存成功');
|
||||||
|
onOpenChange(false);
|
||||||
|
onSuccess?.();
|
||||||
|
} else {
|
||||||
|
toast.error(res.message ?? '保存失败');
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
toast.error('保存失败');
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTagsChange = (value: string) => {
|
||||||
|
// 标签以逗号分隔
|
||||||
|
const tags = value.split(',').map((t) => t.trim()).filter(Boolean);
|
||||||
|
setFormData((prev) => ({ ...prev, tags }));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||||
|
<DialogContent className="sm:max-w-[500px] max-h-[90vh] overflow-y-auto">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>编辑文件描述</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
|
<div className="grid gap-4 py-4">
|
||||||
|
{/* 文件路径(只读) */}
|
||||||
|
<div className="grid gap-2">
|
||||||
|
<Label className="text-slate-400">文件路径</Label>
|
||||||
|
<Input value={formData.filepath} disabled className="font-mono text-xs" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 标题 */}
|
||||||
|
<div className="grid gap-2">
|
||||||
|
<Label htmlFor="title">标题</Label>
|
||||||
|
<Input
|
||||||
|
id="title"
|
||||||
|
value={formData.title}
|
||||||
|
onChange={(e) => setFormData((prev) => ({ ...prev, title: e.target.value }))}
|
||||||
|
placeholder="输入文件标题"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 标签 */}
|
||||||
|
<div className="grid gap-2">
|
||||||
|
<Label htmlFor="tags">标签</Label>
|
||||||
|
<Input
|
||||||
|
id="tags"
|
||||||
|
value={formData.tags?.join(', ') || ''}
|
||||||
|
onChange={(e) => handleTagsChange(e.target.value)}
|
||||||
|
placeholder="输入标签,用逗号分隔"
|
||||||
|
/>
|
||||||
|
<span className="text-[10px] text-slate-500">多个标签用逗号分隔</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 摘要 */}
|
||||||
|
<div className="grid gap-2">
|
||||||
|
<Label htmlFor="summary">摘要</Label>
|
||||||
|
<Input
|
||||||
|
id="summary"
|
||||||
|
value={formData.summary}
|
||||||
|
onChange={(e) => setFormData((prev) => ({ ...prev, summary: e.target.value }))}
|
||||||
|
placeholder="简短描述文件内容"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 链接 */}
|
||||||
|
<div className="grid gap-2">
|
||||||
|
<Label htmlFor="link">链接</Label>
|
||||||
|
<Input
|
||||||
|
id="link"
|
||||||
|
value={formData.link}
|
||||||
|
onChange={(e) => setFormData((prev) => ({ ...prev, link: e.target.value }))}
|
||||||
|
placeholder="关联的外部链接(如文档、Issue 等)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 描述 */}
|
||||||
|
<div className="grid gap-2">
|
||||||
|
<Label htmlFor="description">详细描述</Label>
|
||||||
|
<Textarea
|
||||||
|
id="description"
|
||||||
|
value={formData.description}
|
||||||
|
onChange={(e) => setFormData((prev) => ({ ...prev, description: e.target.value }))}
|
||||||
|
placeholder="详细描述文件内容、用途等"
|
||||||
|
className="min-h-[120px]"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<DialogFooter>
|
||||||
|
<Button variant="outline" onClick={() => onOpenChange(false)}>
|
||||||
|
取消
|
||||||
|
</Button>
|
||||||
|
<Button onClick={handleSave} disabled={loading}>
|
||||||
|
{loading ? '保存中...' : '保存'}
|
||||||
|
</Button>
|
||||||
|
</DialogFooter>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import { createQueryApi } from '@kevisual/query/api';
|
import { createQueryApi } from '@kevisual/query/api';
|
||||||
import { query } from '@/modules/query.ts';
|
|
||||||
const api = {
|
const api = {
|
||||||
"project": {
|
"project": {
|
||||||
/**
|
/**
|
||||||
@@ -41,6 +40,14 @@ const api = {
|
|||||||
"optional": true
|
"optional": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"viewItem": {
|
||||||
|
"api": {
|
||||||
|
"url": "/root/v1/dev-cnb"
|
||||||
|
},
|
||||||
|
"type": "api",
|
||||||
|
"title": "CNB_BOARD",
|
||||||
|
"routerStatus": "active"
|
||||||
|
},
|
||||||
"url": "/root/v1/dev-cnb",
|
"url": "/root/v1/dev-cnb",
|
||||||
"source": "query-proxy-api"
|
"source": "query-proxy-api"
|
||||||
}
|
}
|
||||||
@@ -64,6 +71,14 @@ const api = {
|
|||||||
"description": "要移除的项目根目录绝对路径,必填"
|
"description": "要移除的项目根目录绝对路径,必填"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"viewItem": {
|
||||||
|
"api": {
|
||||||
|
"url": "/root/v1/dev-cnb"
|
||||||
|
},
|
||||||
|
"type": "api",
|
||||||
|
"title": "CNB_BOARD",
|
||||||
|
"routerStatus": "active"
|
||||||
|
},
|
||||||
"url": "/root/v1/dev-cnb",
|
"url": "/root/v1/dev-cnb",
|
||||||
"source": "query-proxy-api"
|
"source": "query-proxy-api"
|
||||||
}
|
}
|
||||||
@@ -87,6 +102,14 @@ const api = {
|
|||||||
"description": "要暂停监听的项目根目录绝对路径,必填"
|
"description": "要暂停监听的项目根目录绝对路径,必填"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"viewItem": {
|
||||||
|
"api": {
|
||||||
|
"url": "/root/v1/dev-cnb"
|
||||||
|
},
|
||||||
|
"type": "api",
|
||||||
|
"title": "CNB_BOARD",
|
||||||
|
"routerStatus": "active"
|
||||||
|
},
|
||||||
"url": "/root/v1/dev-cnb",
|
"url": "/root/v1/dev-cnb",
|
||||||
"source": "query-proxy-api"
|
"source": "query-proxy-api"
|
||||||
}
|
}
|
||||||
@@ -110,6 +133,14 @@ const api = {
|
|||||||
"description": "要查询的项目根目录绝对路径,必填"
|
"description": "要查询的项目根目录绝对路径,必填"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"viewItem": {
|
||||||
|
"api": {
|
||||||
|
"url": "/root/v1/dev-cnb"
|
||||||
|
},
|
||||||
|
"type": "api",
|
||||||
|
"title": "CNB_BOARD",
|
||||||
|
"routerStatus": "active"
|
||||||
|
},
|
||||||
"url": "/root/v1/dev-cnb",
|
"url": "/root/v1/dev-cnb",
|
||||||
"source": "query-proxy-api"
|
"source": "query-proxy-api"
|
||||||
}
|
}
|
||||||
@@ -122,6 +153,14 @@ const api = {
|
|||||||
"key": "list",
|
"key": "list",
|
||||||
"description": "列出所有已注册的项目及其当前运行状态(路径、仓库名称、监听是否活跃等)",
|
"description": "列出所有已注册的项目及其当前运行状态(路径、仓库名称、监听是否活跃等)",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
|
"viewItem": {
|
||||||
|
"api": {
|
||||||
|
"url": "/root/v1/dev-cnb"
|
||||||
|
},
|
||||||
|
"type": "api",
|
||||||
|
"title": "CNB_BOARD",
|
||||||
|
"routerStatus": "active"
|
||||||
|
},
|
||||||
"url": "/root/v1/dev-cnb",
|
"url": "/root/v1/dev-cnb",
|
||||||
"source": "query-proxy-api"
|
"source": "query-proxy-api"
|
||||||
}
|
}
|
||||||
@@ -190,6 +229,45 @@ const api = {
|
|||||||
"optional": true
|
"optional": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"viewItem": {
|
||||||
|
"api": {
|
||||||
|
"url": "/root/v1/dev-cnb"
|
||||||
|
},
|
||||||
|
"type": "api",
|
||||||
|
"title": "CNB_BOARD",
|
||||||
|
"routerStatus": "active"
|
||||||
|
},
|
||||||
|
"url": "/root/v1/dev-cnb",
|
||||||
|
"source": "query-proxy-api"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 列出项目根目录下的所有文件路径,适用于前端展示项目结构
|
||||||
|
*
|
||||||
|
* @param data - Request parameters
|
||||||
|
* @param data.rootPath - {string} 项目根目录绝对路径,默认为 /workspace/projects,指定后只列出该目录下的项目文件
|
||||||
|
*/
|
||||||
|
"project-files": {
|
||||||
|
"path": "project",
|
||||||
|
"key": "project-files",
|
||||||
|
"description": "列出项目根目录下的所有文件路径,适用于前端展示项目结构",
|
||||||
|
"metadata": {
|
||||||
|
"args": {
|
||||||
|
"rootPath": {
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"description": "项目根目录绝对路径,默认为 /workspace/projects,指定后只列出该目录下的项目文件",
|
||||||
|
"type": "string",
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"viewItem": {
|
||||||
|
"api": {
|
||||||
|
"url": "/root/v1/dev-cnb"
|
||||||
|
},
|
||||||
|
"type": "api",
|
||||||
|
"title": "CNB_BOARD",
|
||||||
|
"routerStatus": "active"
|
||||||
|
},
|
||||||
"url": "/root/v1/dev-cnb",
|
"url": "/root/v1/dev-cnb",
|
||||||
"source": "query-proxy-api"
|
"source": "query-proxy-api"
|
||||||
}
|
}
|
||||||
@@ -199,6 +277,7 @@ const api = {
|
|||||||
*
|
*
|
||||||
* @param data - Request parameters
|
* @param data - Request parameters
|
||||||
* @param data.rootPath - {string} 搜索项目的根目录绝对路径,默认为 /workspace/projects
|
* @param data.rootPath - {string} 搜索项目的根目录绝对路径,默认为 /workspace/projects
|
||||||
|
* @param data.projectPaths - {array} 项目路径列表,提供后将直接注册这些路径为项目,忽略rootPath参数
|
||||||
*/
|
*/
|
||||||
"init": {
|
"init": {
|
||||||
"path": "project",
|
"path": "project",
|
||||||
@@ -211,8 +290,25 @@ const api = {
|
|||||||
"description": "搜索项目的根目录绝对路径,默认为 /workspace/projects",
|
"description": "搜索项目的根目录绝对路径,默认为 /workspace/projects",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"optional": true
|
"optional": true
|
||||||
|
},
|
||||||
|
"projectPaths": {
|
||||||
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
"description": "项目路径列表,提供后将直接注册这些路径为项目,忽略rootPath参数",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"optional": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"viewItem": {
|
||||||
|
"api": {
|
||||||
|
"url": "/root/v1/dev-cnb"
|
||||||
|
},
|
||||||
|
"type": "api",
|
||||||
|
"title": "CNB_BOARD",
|
||||||
|
"routerStatus": "active"
|
||||||
|
},
|
||||||
"url": "/root/v1/dev-cnb",
|
"url": "/root/v1/dev-cnb",
|
||||||
"source": "query-proxy-api"
|
"source": "query-proxy-api"
|
||||||
}
|
}
|
||||||
@@ -236,6 +332,14 @@ const api = {
|
|||||||
"optional": true
|
"optional": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"viewItem": {
|
||||||
|
"api": {
|
||||||
|
"url": "/root/v1/dev-cnb"
|
||||||
|
},
|
||||||
|
"type": "api",
|
||||||
|
"title": "CNB_BOARD",
|
||||||
|
"routerStatus": "active"
|
||||||
|
},
|
||||||
"url": "/root/v1/dev-cnb",
|
"url": "/root/v1/dev-cnb",
|
||||||
"source": "query-proxy-api"
|
"source": "query-proxy-api"
|
||||||
}
|
}
|
||||||
@@ -265,6 +369,14 @@ const api = {
|
|||||||
"description": "代码仓库标识,用于搜索结果展示和过滤,格式如 owner/repo,例如 kevisual/cnb,必填"
|
"description": "代码仓库标识,用于搜索结果展示和过滤,格式如 owner/repo,例如 kevisual/cnb,必填"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"viewItem": {
|
||||||
|
"api": {
|
||||||
|
"url": "/root/v1/dev-cnb"
|
||||||
|
},
|
||||||
|
"type": "api",
|
||||||
|
"title": "CNB_BOARD",
|
||||||
|
"routerStatus": "active"
|
||||||
|
},
|
||||||
"url": "/root/v1/dev-cnb",
|
"url": "/root/v1/dev-cnb",
|
||||||
"source": "query-proxy-api"
|
"source": "query-proxy-api"
|
||||||
}
|
}
|
||||||
@@ -376,6 +488,14 @@ const api = {
|
|||||||
"optional": true
|
"optional": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"viewItem": {
|
||||||
|
"api": {
|
||||||
|
"url": "/root/v1/dev-cnb"
|
||||||
|
},
|
||||||
|
"type": "api",
|
||||||
|
"title": "CNB_BOARD",
|
||||||
|
"routerStatus": "active"
|
||||||
|
},
|
||||||
"url": "/root/v1/dev-cnb",
|
"url": "/root/v1/dev-cnb",
|
||||||
"source": "query-proxy-api"
|
"source": "query-proxy-api"
|
||||||
}
|
}
|
||||||
@@ -481,6 +601,14 @@ const api = {
|
|||||||
"optional": true
|
"optional": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"viewItem": {
|
||||||
|
"api": {
|
||||||
|
"url": "/root/v1/dev-cnb"
|
||||||
|
},
|
||||||
|
"type": "api",
|
||||||
|
"title": "CNB_BOARD",
|
||||||
|
"routerStatus": "active"
|
||||||
|
},
|
||||||
"url": "/root/v1/dev-cnb",
|
"url": "/root/v1/dev-cnb",
|
||||||
"source": "query-proxy-api"
|
"source": "query-proxy-api"
|
||||||
}
|
}
|
||||||
@@ -506,6 +634,14 @@ const api = {
|
|||||||
"description": "要读取的文件绝对路径,必填"
|
"description": "要读取的文件绝对路径,必填"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"viewItem": {
|
||||||
|
"api": {
|
||||||
|
"url": "/root/v1/dev-cnb"
|
||||||
|
},
|
||||||
|
"type": "api",
|
||||||
|
"title": "CNB_BOARD",
|
||||||
|
"routerStatus": "active"
|
||||||
|
},
|
||||||
"url": "/root/v1/dev-cnb",
|
"url": "/root/v1/dev-cnb",
|
||||||
"source": "query-proxy-api"
|
"source": "query-proxy-api"
|
||||||
}
|
}
|
||||||
@@ -536,6 +672,14 @@ const api = {
|
|||||||
"description": "文件内容的 base64 编码,必填"
|
"description": "文件内容的 base64 编码,必填"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"viewItem": {
|
||||||
|
"api": {
|
||||||
|
"url": "/root/v1/dev-cnb"
|
||||||
|
},
|
||||||
|
"type": "api",
|
||||||
|
"title": "CNB_BOARD",
|
||||||
|
"routerStatus": "active"
|
||||||
|
},
|
||||||
"url": "/root/v1/dev-cnb",
|
"url": "/root/v1/dev-cnb",
|
||||||
"source": "query-proxy-api"
|
"source": "query-proxy-api"
|
||||||
}
|
}
|
||||||
@@ -597,6 +741,14 @@ const api = {
|
|||||||
"optional": true
|
"optional": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"viewItem": {
|
||||||
|
"api": {
|
||||||
|
"url": "/root/v1/dev-cnb"
|
||||||
|
},
|
||||||
|
"type": "api",
|
||||||
|
"title": "CNB_BOARD",
|
||||||
|
"routerStatus": "active"
|
||||||
|
},
|
||||||
"url": "/root/v1/dev-cnb",
|
"url": "/root/v1/dev-cnb",
|
||||||
"source": "query-proxy-api"
|
"source": "query-proxy-api"
|
||||||
}
|
}
|
||||||
@@ -620,12 +772,20 @@ const api = {
|
|||||||
"description": "要删除的文件绝对路径,必填"
|
"description": "要删除的文件绝对路径,必填"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"viewItem": {
|
||||||
|
"api": {
|
||||||
|
"url": "/root/v1/dev-cnb"
|
||||||
|
},
|
||||||
|
"type": "api",
|
||||||
|
"title": "CNB_BOARD",
|
||||||
|
"routerStatus": "active"
|
||||||
|
},
|
||||||
"url": "/root/v1/dev-cnb",
|
"url": "/root/v1/dev-cnb",
|
||||||
"source": "query-proxy-api"
|
"source": "query-proxy-api"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} as const;
|
} as const;
|
||||||
const queryApi = createQueryApi({ api, query });
|
const queryApi = createQueryApi({ api });
|
||||||
|
|
||||||
export { queryApi };
|
export { queryApi };
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
import { FileIcon, FolderIcon, DatabaseIcon, XIcon, MoveIcon, SquarePenIcon, BotIcon } from 'lucide-react';
|
import { FileIcon, FolderIcon, DatabaseIcon, XIcon, MoveIcon, SquarePenIcon, BotIcon, FileTextIcon } from 'lucide-react';
|
||||||
import { useCodeGraphStore, NodeInfoData } from '../store';
|
import { useCodeGraphStore, NodeInfoData } from '../store';
|
||||||
import { useBotHelperStore } from '../store/bot-helper';
|
import { useBotHelperStore } from '../store/bot-helper';
|
||||||
import { useShallow } from 'zustand/react/shallow';
|
import { useShallow } from 'zustand/react/shallow';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
import { FileDescriptionDialog, FileDescriptionData } from '@/components/FileDescriptionDialog';
|
||||||
|
|
||||||
function KindIcon({ kind, color }: { kind: NodeInfoData['kind']; color: string }) {
|
function KindIcon({ kind, color }: { kind: NodeInfoData['kind']; color: string }) {
|
||||||
const cls = 'size-4 shrink-0';
|
const cls = 'size-4 shrink-0';
|
||||||
@@ -94,6 +95,17 @@ export const NodeInfoContainer = () => {
|
|||||||
const [offset, setOffset] = useState({ x: 0, y: 0 });
|
const [offset, setOffset] = useState({ x: 0, y: 0 });
|
||||||
const [pinLeft, setPinLeft] = useState(false); // 编辑后固定到右下角
|
const [pinLeft, setPinLeft] = useState(false); // 编辑后固定到右下角
|
||||||
|
|
||||||
|
// 描述弹窗
|
||||||
|
const [descriptionOpen, setDescriptionOpen] = useState(false);
|
||||||
|
const [descriptionData, setDescriptionData] = useState<FileDescriptionData>({
|
||||||
|
filepath: '',
|
||||||
|
title: '',
|
||||||
|
tags: [],
|
||||||
|
summary: '',
|
||||||
|
description: '',
|
||||||
|
link: '',
|
||||||
|
});
|
||||||
|
|
||||||
// 检测屏幕大小
|
// 检测屏幕大小
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const checkMobile = () => setIsMobile(window.innerWidth < 768);
|
const checkMobile = () => setIsMobile(window.innerWidth < 768);
|
||||||
@@ -169,6 +181,23 @@ export const NodeInfoContainer = () => {
|
|||||||
className='ml-1 text-slate-500 hover:text-indigo-400 transition-colors'>
|
className='ml-1 text-slate-500 hover:text-indigo-400 transition-colors'>
|
||||||
<SquarePenIcon className='size-3.5' />
|
<SquarePenIcon className='size-3.5' />
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
if (!nodeInfoData) return;
|
||||||
|
setDescriptionData({
|
||||||
|
filepath: nodeInfoData.fullPath,
|
||||||
|
title: nodeInfoData.title,
|
||||||
|
tags: nodeInfoData.tags,
|
||||||
|
summary: nodeInfoData.summary,
|
||||||
|
description: nodeInfoData.description,
|
||||||
|
link: nodeInfoData.link,
|
||||||
|
});
|
||||||
|
setDescriptionOpen(true);
|
||||||
|
}}
|
||||||
|
title='编辑描述'
|
||||||
|
className='ml-1 text-slate-500 hover:text-amber-400 transition-colors'>
|
||||||
|
<FileTextIcon className='size-3.5' />
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
botHelperStore.setProjectInfo({
|
botHelperStore.setProjectInfo({
|
||||||
@@ -194,6 +223,15 @@ export const NodeInfoContainer = () => {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<NodeInfo />
|
<NodeInfo />
|
||||||
|
{/* 描述编辑弹窗 */}
|
||||||
|
<FileDescriptionDialog
|
||||||
|
open={descriptionOpen}
|
||||||
|
onOpenChange={setDescriptionOpen}
|
||||||
|
data={descriptionData}
|
||||||
|
onSuccess={() => {
|
||||||
|
// 可选:刷新节点数据
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,11 @@ export type NodeInfoData = {
|
|||||||
color: string;
|
color: string;
|
||||||
fileId?: string;
|
fileId?: string;
|
||||||
nodeSize?: number;
|
nodeSize?: number;
|
||||||
|
title?: string;
|
||||||
|
tags?: string[];
|
||||||
|
summary?: string;
|
||||||
|
description?: string;
|
||||||
|
link?: string;
|
||||||
};
|
};
|
||||||
export type OpencodeResult = {
|
export type OpencodeResult = {
|
||||||
info: AssistantMessage;
|
info: AssistantMessage;
|
||||||
|
|||||||
Reference in New Issue
Block a user