1
0
mirror of https://github.com/lencx/ChatGPT.git synced 2024-10-01 01:06:13 -04:00

chore: path

This commit is contained in:
lencx 2023-01-18 00:03:45 +08:00
parent f38d683f4e
commit a7d12bafc0
16 changed files with 144 additions and 56 deletions

View File

@ -34,13 +34,16 @@
}, },
"dependencies": { "dependencies": {
"@ant-design/icons": "^4.8.0", "@ant-design/icons": "^4.8.0",
"@monaco-editor/react": "^4.4.6",
"@tauri-apps/api": "^1.2.0", "@tauri-apps/api": "^1.2.0",
"antd": "^5.1.0", "antd": "^5.1.0",
"clsx": "^1.2.1",
"dayjs": "^1.11.7", "dayjs": "^1.11.7",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-markdown": "^8.0.4", "react-markdown": "^8.0.4",
"react-resizable-panels": "^0.0.33",
"react-router-dom": "^6.4.5", "react-router-dom": "^6.4.5",
"react-syntax-highlighter": "^15.5.0", "react-syntax-highlighter": "^15.5.0",
"uuid": "^9.0.0" "uuid": "^9.0.0"

36
src/components/FilePath/index.tsx vendored Normal file
View File

@ -0,0 +1,36 @@
import { FC, useEffect, useState } from 'react';
import clsx from 'clsx';
import { path, shell } from '@tauri-apps/api';
import { chatRoot } from '@/utils';
interface FilePathProps {
paths?: string;
label?: string;
className?: string;
content?: string;
url?: string;
}
const FilePath: FC<FilePathProps> = ({ className, label = 'PATH', paths = '', url, content }) => {
const [filePath, setPath] = useState('');
useEffect(() => {
if (!path && !url) return;
(async () => {
if (url) {
setPath(url);
return;
}
setPath(await path.join(await chatRoot(), ...paths.split('/').filter(i => !!i)));
})()
}, [url, paths])
return (
<div className={clsx(className, 'chat-file-path')}>
<div>{label}: <a onClick={() => shell.open(filePath)} title={filePath}>{content ? content : filePath}</a></div>
</div>
);
}
export default FilePath;

25
src/components/Markdown/Editor.tsx vendored Normal file
View File

@ -0,0 +1,25 @@
import Editor from "@monaco-editor/react";
import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
import './index.scss';
const MarkdownEditor = () => {
return (
<div>
<PanelGroup direction="horizontal">
<Panel>
<Editor
height="calc(100vh - 120px)"
language="markdown"
/>
</Panel>
<PanelResizeHandle className="resize-handle" />
<Panel collapsible={true}>
<div>1284</div>
</Panel>
</PanelGroup>
</div>
)
};
export default MarkdownEditor;

View File

@ -5,3 +5,15 @@
font-family: monospace, monospace; font-family: monospace, monospace;
} }
} }
.resize-handle {
width: 0.25rem;
transition: 250ms linear background-color;
background-color: #7f8082;
outline: none;
&:hover,
&[data-resize-handle-active] {
background-color: #5194eb;
}
}

1
src/main.scss vendored
View File

@ -19,6 +19,7 @@ html, body {
margin: 0; margin: 0;
} }
.ant-table-selection-col,
.ant-table-selection-column { .ant-table-selection-column {
width: 50px !important; width: 50px !important;
min-width: 50px !important; min-width: 50px !important;

6
src/routes.tsx vendored
View File

@ -17,6 +17,7 @@ import SyncCustom from '@/view/model/SyncCustom';
import SyncRecord from '@/view/model/SyncRecord'; import SyncRecord from '@/view/model/SyncRecord';
import Download from '@/view/download'; import Download from '@/view/download';
import Notes from '@/view/notes'; import Notes from '@/view/notes';
import Markdown from '@/view/markdown';
export type ChatRouteMetaObject = { export type ChatRouteMetaObject = {
label: string; label: string;
@ -48,6 +49,11 @@ export const routes: Array<ChatRouteObject> = [
icon: <FormOutlined />, icon: <FormOutlined />,
}, },
}, },
{
path: '/md/:id',
element: <Markdown />,
hideMenu: true,
},
{ {
path: '/model', path: '/model',
meta: { meta: {

1
src/utils.ts vendored
View File

@ -2,6 +2,7 @@ import { readTextFile, writeTextFile, exists, createDir } from '@tauri-apps/api/
import { homeDir, join, dirname } from '@tauri-apps/api/path'; import { homeDir, join, dirname } from '@tauri-apps/api/path';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
export const CHAT_CONF_JSON = 'chat.conf.json';
export const CHAT_MODEL_JSON = 'chat.model.json'; export const CHAT_MODEL_JSON = 'chat.model.json';
export const CHAT_MODEL_CMD_JSON = 'chat.model.cmd.json'; export const CHAT_MODEL_CMD_JSON = 'chat.model.cmd.json';
export const CHAT_DOWNLOAD_JSON = 'chat.download.json'; export const CHAT_DOWNLOAD_JSON = 'chat.download.json';

14
src/view/General.tsx vendored
View File

@ -1,14 +1,15 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { Form, Radio, Switch, Input, Button, Space, message, Tooltip } from 'antd'; import { Form, Radio, Switch, Input, Button, Space, message, Tooltip } from 'antd';
import { QuestionCircleOutlined } from '@ant-design/icons'; import { QuestionCircleOutlined } from '@ant-design/icons';
import { invoke, shell, path } from '@tauri-apps/api'; import { invoke } from '@tauri-apps/api';
import { platform } from '@tauri-apps/api/os'; import { platform } from '@tauri-apps/api/os';
import { ask } from '@tauri-apps/api/dialog'; import { ask } from '@tauri-apps/api/dialog';
import { relaunch } from '@tauri-apps/api/process'; import { relaunch } from '@tauri-apps/api/process';
import { clone, omit, isEqual } from 'lodash'; import { clone, omit, isEqual } from 'lodash';
import useInit from '@/hooks/useInit'; import useInit from '@/hooks/useInit';
import { DISABLE_AUTO_COMPLETE, chatRoot } from '@/utils'; import FilePath from '@/components/FilePath';
import { DISABLE_AUTO_COMPLETE, CHAT_CONF_JSON } from '@/utils';
const AutoUpdateLabel = () => { const AutoUpdateLabel = () => {
return ( return (
@ -68,13 +69,10 @@ const GlobalShortcutLabel = () => {
export default function General() { export default function General() {
const [form] = Form.useForm(); const [form] = Form.useForm();
const [jsonPath, setJsonPath] = useState('');
const [platformInfo, setPlatform] = useState<string>(''); const [platformInfo, setPlatform] = useState<string>('');
const [chatConf, setChatConf] = useState<any>(null); const [chatConf, setChatConf] = useState<any>(null);
useInit(async () => { useInit(async () => {
setJsonPath(await path.join(await chatRoot(), 'chat.conf.json'));
setPlatform(await platform()); setPlatform(await platform());
const chatData = await invoke('get_chat_conf'); const chatData = await invoke('get_chat_conf');
setChatConf(chatData); setChatConf(chatData);
@ -117,11 +115,7 @@ export default function General() {
return ( return (
<> <>
<div className="chat-table-tip"> <FilePath paths={CHAT_CONF_JSON} />
<div className="chat-sync-path">
<div>PATH: <a onClick={() => shell.open(jsonPath)} title={jsonPath}>{jsonPath}</a></div>
</div>
</div>
<Form <Form
form={form} form={form}
style={{ maxWidth: 500 }} style={{ maxWidth: 500 }}

View File

@ -1,11 +1,11 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { Table, Modal, Popconfirm, Button, message } from 'antd'; import { Table, Modal, Popconfirm, Button, message } from 'antd';
import { invoke, path, shell, fs } from '@tauri-apps/api'; import { invoke, path, fs } from '@tauri-apps/api';
import useInit from '@/hooks/useInit';
import useJson from '@/hooks/useJson'; import useJson from '@/hooks/useJson';
import useData from '@/hooks/useData'; import useData from '@/hooks/useData';
import useColumns from '@/hooks/useColumns'; import useColumns from '@/hooks/useColumns';
import FilePath from '@/components/FilePath';
import { useTableRowSelection, TABLE_PAGINATION } from '@/hooks/useTable'; import { useTableRowSelection, TABLE_PAGINATION } from '@/hooks/useTable';
import { chatRoot, CHAT_DOWNLOAD_JSON } from '@/utils'; import { chatRoot, CHAT_DOWNLOAD_JSON } from '@/utils';
import { downloadColumns } from './config'; import { downloadColumns } from './config';
@ -19,7 +19,6 @@ function renderFile(buff: Uint8Array, type: string) {
} }
export default function Download() { export default function Download() {
const [downloadPath, setDownloadPath] = useState('');
const [source, setSource] = useState(''); const [source, setSource] = useState('');
const [isVisible, setVisible] = useState(false); const [isVisible, setVisible] = useState(false);
const { opData, opInit, opReplace, opSafeKey } = useData([]); const { opData, opInit, opReplace, opSafeKey } = useData([]);
@ -28,11 +27,6 @@ export default function Download() {
const { json, refreshJson, updateJson } = useJson<any[]>(CHAT_DOWNLOAD_JSON); const { json, refreshJson, updateJson } = useJson<any[]>(CHAT_DOWNLOAD_JSON);
const selectedItems = rowSelection.selectedRowKeys || []; const selectedItems = rowSelection.selectedRowKeys || [];
useInit(async () => {
const file = await path.join(await chatRoot(), CHAT_DOWNLOAD_JSON);
setDownloadPath(file);
});
useEffect(() => { useEffect(() => {
if (!json || json.length <= 0) return; if (!json || json.length <= 0) return;
opInit(json); opInit(json);
@ -118,11 +112,7 @@ export default function Download() {
)} )}
</div> </div>
</div> </div>
<div className="chat-table-tip"> <FilePath paths={CHAT_DOWNLOAD_JSON} />
<div className="chat-file-path">
<div>PATH: <a onClick={() => shell.open(downloadPath)} title={downloadPath}>{downloadPath}</a></div>
</div>
</div>
<Table <Table
rowKey="id" rowKey="id"
columns={columns} columns={columns}

32
src/view/markdown/index.tsx vendored Normal file
View File

@ -0,0 +1,32 @@
import { useState } from 'react';
import { useLocation } from 'react-router-dom';
import { Breadcrumb } from 'antd';
import { ArrowLeftOutlined } from '@ant-design/icons';
import MarkdownEditor from '@/components/Markdown/Editor';
import useInit from '@/hooks/useInit';
import { getPath } from '@/view/notes/config';
export default function Markdown() {
const [filePath, setFilePath] = useState('');
const location = useLocation();
const state = location?.state;
useInit(async () => {
setFilePath(await getPath(state));
})
return (
<>
<Breadcrumb separator=" ">
<Breadcrumb.Item href="">
<ArrowLeftOutlined />
</Breadcrumb.Item>
<Breadcrumb.Item href="">
{filePath}
</Breadcrumb.Item>
</Breadcrumb>
<MarkdownEditor />
</>
);
}

View File

@ -3,9 +3,9 @@ import { Table, Modal, Button, message } from 'antd';
import { invoke, path, fs } from '@tauri-apps/api'; import { invoke, path, fs } from '@tauri-apps/api';
import useData from '@/hooks/useData'; import useData from '@/hooks/useData';
import useChatModel, { useCacheModel } from '@/hooks/useChatModel';
import useColumns from '@/hooks/useColumns'; import useColumns from '@/hooks/useColumns';
import { TABLE_PAGINATION } from '@/hooks/useTable'; import { TABLE_PAGINATION } from '@/hooks/useTable';
import useChatModel, { useCacheModel } from '@/hooks/useChatModel';
import { CHAT_MODEL_JSON, chatRoot, readJSON, genCmd } from '@/utils'; import { CHAT_MODEL_JSON, chatRoot, readJSON, genCmd } from '@/utils';
import { syncColumns, getPath } from './config'; import { syncColumns, getPath } from './config';
import SyncForm from './Form'; import SyncForm from './Form';

View File

@ -1,10 +1,11 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { Table, Button, Popconfirm } from 'antd'; import { Table, Button, Popconfirm } from 'antd';
import { invoke, path, shell } from '@tauri-apps/api'; import { invoke, path } from '@tauri-apps/api';
import useInit from '@/hooks/useInit'; import useInit from '@/hooks/useInit';
import useData from '@/hooks/useData'; import useData from '@/hooks/useData';
import useColumns from '@/hooks/useColumns'; import useColumns from '@/hooks/useColumns';
import FilePath from '@/components/FilePath';
import useChatModel, { useCacheModel } from '@/hooks/useChatModel'; import useChatModel, { useCacheModel } from '@/hooks/useChatModel';
import { useTableRowSelection, TABLE_PAGINATION } from '@/hooks/useTable'; import { useTableRowSelection, TABLE_PAGINATION } from '@/hooks/useTable';
import { fmtDate, chatRoot } from '@/utils'; import { fmtDate, chatRoot } from '@/utils';
@ -80,8 +81,8 @@ export default function SyncPrompts() {
</div> </div>
<div className="chat-table-tip"> <div className="chat-table-tip">
<div className="chat-sync-path"> <div className="chat-sync-path">
<div>PATH: <a onClick={() => shell.open(promptsURL)} target="_blank" title={promptsURL}>f/awesome-chatgpt-prompts/prompts.csv</a></div> <FilePath url={promptsURL} content="f/awesome-chatgpt-prompts/prompts.csv" />
<div>CACHE: <a onClick={() => shell.open(jsonPath)} target="_blank" title={jsonPath}>{jsonPath}</a></div> <FilePath label="CACHE" paths="cache_model/chatgpt_prompts.json" />
</div> </div>
{lastUpdated && <span style={{ marginLeft: 10, color: '#888', fontSize: 12 }}>Last updated on {fmtDate(lastUpdated)}</span>} {lastUpdated && <span style={{ marginLeft: 10, color: '#888', fontSize: 12 }}>Last updated on {fmtDate(lastUpdated)}</span>}
</div> </div>

View File

@ -2,14 +2,15 @@ import { useEffect, useState } from 'react';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import { ArrowLeftOutlined } from '@ant-design/icons'; import { ArrowLeftOutlined } from '@ant-design/icons';
import { Table, Button } from 'antd'; import { Table, Button } from 'antd';
import { shell, path } from '@tauri-apps/api'; import { path } from '@tauri-apps/api';
import useColumns from '@/hooks/useColumns';
import useData from '@/hooks/useData'; import useData from '@/hooks/useData';
import useColumns from '@/hooks/useColumns';
import FilePath from '@/components/FilePath';
import { useCacheModel } from '@/hooks/useChatModel'; import { useCacheModel } from '@/hooks/useChatModel';
import { useTableRowSelection, TABLE_PAGINATION } from '@/hooks/useTable'; import { useTableRowSelection, TABLE_PAGINATION } from '@/hooks/useTable';
import { fmtDate, chatRoot } from '@/utils';
import { getPath } from '@/view/model/SyncCustom/config'; import { getPath } from '@/view/model/SyncCustom/config';
import { fmtDate, chatRoot } from '@/utils';
import { syncColumns } from './config'; import { syncColumns } from './config';
import useInit from '@/hooks/useInit'; import useInit from '@/hooks/useInit';
@ -66,8 +67,8 @@ export default function SyncRecord() {
</div> </div>
<div className="chat-table-tip"> <div className="chat-table-tip">
<div className="chat-sync-path"> <div className="chat-sync-path">
<div>PATH: <a onClick={() => shell.open(filePath)} target="_blank" title={filePath}>{filePath}</a></div> <FilePath url={filePath} />
<div>CACHE: <a onClick={() => shell.open(jsonPath)} target="_blank" title={jsonPath}>{jsonPath}</a></div> <FilePath label="CACHE" paths={`cache_model/${state?.id}.json`} />
</div> </div>
{state?.last_updated && <span style={{ marginLeft: 10, color: '#888', fontSize: 12 }}>Last updated on {fmtDate(state?.last_updated)}</span>} {state?.last_updated && <span style={{ marginLeft: 10, color: '#888', fontSize: 12 }}>Last updated on {fmtDate(state?.last_updated)}</span>}
</div> </div>

View File

@ -1,11 +1,12 @@
import { useState, useRef, useEffect } from 'react'; import { useState, useRef, useEffect } from 'react';
import { Table, Button, Modal, message } from 'antd'; import { Table, Button, Modal, message } from 'antd';
import { shell, path } from '@tauri-apps/api'; import { path } from '@tauri-apps/api';
import useInit from '@/hooks/useInit'; import useInit from '@/hooks/useInit';
import useData from '@/hooks/useData'; import useData from '@/hooks/useData';
import useChatModel, { useCacheModel } from '@/hooks/useChatModel';
import useColumns from '@/hooks/useColumns'; import useColumns from '@/hooks/useColumns';
import FilePath from '@/components/FilePath';
import useChatModel, { useCacheModel } from '@/hooks/useChatModel';
import { useTableRowSelection, TABLE_PAGINATION } from '@/hooks/useTable'; import { useTableRowSelection, TABLE_PAGINATION } from '@/hooks/useTable';
import { chatRoot, fmtDate } from '@/utils'; import { chatRoot, fmtDate } from '@/utils';
import { modelColumns } from './config'; import { modelColumns } from './config';
@ -108,11 +109,8 @@ export default function LanguageModel() {
)} )}
</div> </div>
</div> </div>
{/* <div className="chat-model-path">PATH: <span onClick={handleOpenFile}>{modelPath}</span></div> */}
<div className="chat-table-tip"> <div className="chat-table-tip">
<div className="chat-sync-path"> <FilePath label="CACHE" paths="cache_model/user_custom.json" />
<div>CACHE: <a onClick={() => shell.open(jsonPath)} title={jsonPath}>{jsonPath}</a></div>
</div>
{lastUpdated && <span style={{ marginLeft: 10, color: '#888', fontSize: 12 }}>Last updated on {fmtDate(lastUpdated)}</span>} {lastUpdated && <span style={{ marginLeft: 10, color: '#888', fontSize: 12 }}>Last updated on {fmtDate(lastUpdated)}</span>}
</div> </div>
<Table <Table

View File

@ -1,4 +1,5 @@
import { useState } from 'react'; import { useState } from 'react';
import { Link } from 'react-router-dom';
import { Space, Popconfirm } from 'antd'; import { Space, Popconfirm } from 'antd';
import { path, shell } from '@tauri-apps/api'; import { path, shell } from '@tauri-apps/api';
@ -40,7 +41,7 @@ export const notesColumns = () => [
return ( return (
<Space> <Space>
<a onClick={() => actions.setRecord(row, 'preview')}>Preview</a> <a onClick={() => actions.setRecord(row, 'preview')}>Preview</a>
<a onClick={() => actions.setRecord(row, 'edit')}>Edit</a> <Link to={`/md/${row.id}`} state={row}>Edit</Link>
<Popconfirm <Popconfirm
title="Are you sure to delete this file?" title="Are you sure to delete this file?"
onConfirm={() => actions.setRecord(row, 'delete')} onConfirm={() => actions.setRecord(row, 'delete')}

View File

@ -1,18 +1,17 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { Table, Modal, Popconfirm, Button, message } from 'antd'; import { Table, Modal, Popconfirm, Button, message } from 'antd';
import { invoke, path, shell, fs } from '@tauri-apps/api'; import { invoke, path, fs } from '@tauri-apps/api';
import useInit from '@/hooks/useInit';
import useJson from '@/hooks/useJson'; import useJson from '@/hooks/useJson';
import useData from '@/hooks/useData'; import useData from '@/hooks/useData';
import useColumns from '@/hooks/useColumns'; import useColumns from '@/hooks/useColumns';
import Markdown from '@/components/Markdown'; import Markdown from '@/components/Markdown';
import FilePath from '@/components/FilePath';
import { useTableRowSelection, TABLE_PAGINATION } from '@/hooks/useTable'; import { useTableRowSelection, TABLE_PAGINATION } from '@/hooks/useTable';
import { chatRoot, CHAT_NOTES_JSON } from '@/utils'; import { chatRoot, CHAT_NOTES_JSON } from '@/utils';
import { notesColumns } from './config'; import { notesColumns } from './config';
export default function Notes() { export default function Notes() {
const [notesPath, setNotesPath] = useState('');
const [source, setSource] = useState(''); const [source, setSource] = useState('');
const [isVisible, setVisible] = useState(false); const [isVisible, setVisible] = useState(false);
const { opData, opInit, opReplace, opSafeKey } = useData([]); const { opData, opInit, opReplace, opSafeKey } = useData([]);
@ -21,11 +20,6 @@ export default function Notes() {
const { json, refreshJson, updateJson } = useJson<any[]>(CHAT_NOTES_JSON); const { json, refreshJson, updateJson } = useJson<any[]>(CHAT_NOTES_JSON);
const selectedItems = rowSelection.selectedRowKeys || []; const selectedItems = rowSelection.selectedRowKeys || [];
useInit(async () => {
const file = await path.join(await chatRoot(), CHAT_NOTES_JSON);
setNotesPath(file);
});
useEffect(() => { useEffect(() => {
if (!json || json.length <= 0) return; if (!json || json.length <= 0) return;
opInit(json); opInit(json);
@ -42,9 +36,6 @@ export default function Notes() {
setVisible(true); setVisible(true);
return; return;
} }
if (opInfo.opType === 'edit') {
alert('TODO');
}
if (opInfo.opType === 'delete') { if (opInfo.opType === 'delete') {
await fs.removeFile(file); await fs.removeFile(file);
await handleRefresh(); await handleRefresh();
@ -111,11 +102,7 @@ export default function Notes() {
)} )}
</div> </div>
</div> </div>
<div className="chat-table-tip"> <FilePath paths={CHAT_NOTES_JSON} />
<div className="chat-file-path">
<div>PATH: <a onClick={() => shell.open(notesPath)} title={notesPath}>{notesPath}</a></div>
</div>
</div>
<Table <Table
rowKey="id" rowKey="id"
columns={columns} columns={columns}