mirror of
https://github.com/FranP-code/ChatGPT.git
synced 2025-10-13 00:13:25 +00:00
chore: dashboard
This commit is contained in:
6
src/components/Markdown/index.scss
vendored
6
src/components/Markdown/index.scss
vendored
@@ -13,12 +13,6 @@
|
||||
code {
|
||||
font-family: monospace, monospace;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: rgba(200, 200, 200, 0.4);
|
||||
padding: 2px 4px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.md-main {
|
||||
|
||||
4
src/components/SwitchOrigin/index.tsx
vendored
4
src/components/SwitchOrigin/index.tsx
vendored
@@ -28,7 +28,7 @@ const SwitchOrigin: FC<SwitchOriginProps> = ({ name }) => {
|
||||
title={
|
||||
<div>
|
||||
<p>
|
||||
<b>Set the URL dashboard as an application window.</b>
|
||||
<b>Set Dashboard as the application default window.</b>
|
||||
</p>
|
||||
<p>
|
||||
If this is enabled, the <Tag color="blue">Switch Origin {labelName}</Tag>{' '}
|
||||
@@ -58,7 +58,7 @@ const SwitchOrigin: FC<SwitchOriginProps> = ({ name }) => {
|
||||
title={
|
||||
<div>
|
||||
<p>
|
||||
<b>Set a single URL as an application window.</b>
|
||||
<b>Set a single URL as the application default window.</b>
|
||||
</p>
|
||||
<p>
|
||||
If you need to set a new URL as the application loading window, please add the
|
||||
|
||||
17
src/hooks/useData.ts
vendored
17
src/hooks/useData.ts
vendored
@@ -28,6 +28,12 @@ export default function useData(oData: any[]) {
|
||||
return nData;
|
||||
};
|
||||
|
||||
const opRemoveItems = (ids: string[]) => {
|
||||
const nData = opData.filter((i) => !ids.includes(i[safeKey]));
|
||||
setData(nData);
|
||||
return nData;
|
||||
};
|
||||
|
||||
const opReplace = (id: string, data: any) => {
|
||||
const nData = [...opData];
|
||||
const idx = opData.findIndex((v) => v[safeKey] === id);
|
||||
@@ -51,5 +57,14 @@ export default function useData(oData: any[]) {
|
||||
return nData;
|
||||
};
|
||||
|
||||
return { opSafeKey: safeKey, opInit, opReplace, opAdd, opRemove, opData, opReplaceItems };
|
||||
return {
|
||||
opSafeKey: safeKey,
|
||||
opInit,
|
||||
opReplace,
|
||||
opAdd,
|
||||
opRemove,
|
||||
opRemoveItems,
|
||||
opData,
|
||||
opReplaceItems,
|
||||
};
|
||||
}
|
||||
|
||||
5
src/layout/index.tsx
vendored
5
src/layout/index.tsx
vendored
@@ -21,7 +21,10 @@ export default function ChatLayout() {
|
||||
|
||||
useEffect(() => {
|
||||
if (location.search === '?type=control') {
|
||||
go('/awesome');
|
||||
go('/settings');
|
||||
}
|
||||
if (location.search === '?type=preview') {
|
||||
go('/?type=preview');
|
||||
}
|
||||
setMenuKey(location.pathname);
|
||||
setDashboard(location.pathname === '/');
|
||||
|
||||
6
src/main.scss
vendored
6
src/main.scss
vendored
@@ -103,3 +103,9 @@ body,
|
||||
.chatico {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.awesome-tips {
|
||||
.ant-tag {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
16
src/routes.tsx
vendored
16
src/routes.tsx
vendored
@@ -38,6 +38,14 @@ type ChatRouteObject = {
|
||||
};
|
||||
|
||||
export const routes: Array<ChatRouteObject> = [
|
||||
{
|
||||
path: '/settings',
|
||||
element: <Settings />,
|
||||
meta: {
|
||||
label: 'Settings',
|
||||
icon: <SettingOutlined />,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/awesome',
|
||||
element: <Awesome />,
|
||||
@@ -106,14 +114,6 @@ export const routes: Array<ChatRouteObject> = [
|
||||
icon: <DownloadOutlined />,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/settings',
|
||||
element: <Settings />,
|
||||
meta: {
|
||||
label: 'Settings',
|
||||
icon: <SettingOutlined />,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: '/about',
|
||||
element: <About />,
|
||||
|
||||
6
src/view/about/index.scss
vendored
6
src/view/about/index.scss
vendored
@@ -15,4 +15,10 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: rgba(200, 200, 200, 0.4);
|
||||
padding: 2px 4px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
6
src/view/awesome/Form.tsx
vendored
6
src/view/awesome/Form.tsx
vendored
@@ -43,7 +43,11 @@ const AwesomeForm: ForwardRefRenderFunction<FormProps, AwesomeFormProps> = ({ re
|
||||
>
|
||||
<Input placeholder="Please enter the URL" {...DISABLE_AUTO_COMPLETE} />
|
||||
</Form.Item>
|
||||
<Form.Item label="Category" name="category">
|
||||
<Form.Item
|
||||
label="Category"
|
||||
name="category"
|
||||
rules={[{ required: true, message: 'Please enter a category' }]}
|
||||
>
|
||||
<Input placeholder="Please enter a category" {...DISABLE_AUTO_COMPLETE} />
|
||||
</Form.Item>
|
||||
<Form.Item label="Tags" name="tags">
|
||||
|
||||
72
src/view/awesome/index.tsx
vendored
72
src/view/awesome/index.tsx
vendored
@@ -1,5 +1,8 @@
|
||||
import { useRef, useEffect, useState } from 'react';
|
||||
import { Table, Modal, Popconfirm, Button, message } from 'antd';
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
import { Table, Modal, Popconfirm, Button, Tooltip, Tag, message } from 'antd';
|
||||
import { QuestionCircleOutlined } from '@ant-design/icons';
|
||||
import { invoke } from '@tauri-apps/api';
|
||||
|
||||
import useJson from '@/hooks/useJson';
|
||||
import useData from '@/hooks/useData';
|
||||
@@ -13,9 +16,10 @@ import AwesomeForm from './Form';
|
||||
export default function Awesome() {
|
||||
const formRef = useRef<any>(null);
|
||||
const [isVisible, setVisible] = useState(false);
|
||||
const { opData, opInit, opAdd, opReplace, opReplaceItems, opRemove, opSafeKey } = useData([]);
|
||||
const { opData, opInit, opAdd, opReplace, opReplaceItems, opRemove, opRemoveItems, opSafeKey } =
|
||||
useData([]);
|
||||
const { columns, ...opInfo } = useColumns(awesomeColumns());
|
||||
const { rowSelection, selectedRowIDs } = useTableRowSelection();
|
||||
const { rowSelection, selectedRowIDs, rowReset } = useTableRowSelection();
|
||||
const { json, updateJson } = useJson<any[]>(CHAT_AWESOME_JSON);
|
||||
const selectedItems = rowSelection.selectedRowKeys || [];
|
||||
|
||||
@@ -48,11 +52,19 @@ export default function Awesome() {
|
||||
}
|
||||
}, [opInfo.opTime]);
|
||||
|
||||
const handleDelete = () => {};
|
||||
const handleDelete = () => {
|
||||
const data = opRemoveItems(selectedRowIDs);
|
||||
updateJson(data);
|
||||
rowReset();
|
||||
message.success('All selected URLs have been deleted');
|
||||
};
|
||||
|
||||
const handleOk = () => {
|
||||
formRef.current?.form?.validateFields().then(async (vals: Record<string, any>) => {
|
||||
const idx = opData.findIndex((i) => i.url === vals.url);
|
||||
let idx = opData.findIndex((i) => i.url === vals.url);
|
||||
if (vals.url === opInfo?.opRecord?.url) {
|
||||
idx = -1;
|
||||
}
|
||||
if (idx === -1) {
|
||||
if (opInfo.opType === 'new') {
|
||||
const data = opAdd(vals);
|
||||
@@ -87,14 +99,28 @@ export default function Awesome() {
|
||||
updateJson(data);
|
||||
};
|
||||
|
||||
const handlePreview = () => {
|
||||
invoke('wa_window', {
|
||||
label: 'awesome_preview',
|
||||
url: 'index.html?type=preview',
|
||||
title: 'Preview Dashboard',
|
||||
});
|
||||
};
|
||||
|
||||
const modalTitle = `${{ new: 'Create', edit: 'Edit' }[opInfo.opType]} URL`;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="chat-table-btns">
|
||||
<Button className="chat-add-btn" type="primary" onClick={opInfo.opNew}>
|
||||
Add URL
|
||||
</Button>
|
||||
<div>
|
||||
<Button className="chat-add-btn" type="primary" onClick={opInfo.opNew}>
|
||||
Add URL
|
||||
</Button>
|
||||
<Button type="dashed" onClick={handlePreview}>
|
||||
Preview Dashboard
|
||||
</Button>
|
||||
<PreviewTip />
|
||||
</div>
|
||||
<div>
|
||||
{selectedItems.length > 0 && (
|
||||
<>
|
||||
@@ -139,3 +165,33 @@ export default function Awesome() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const PreviewTip = () => {
|
||||
const go = useNavigate();
|
||||
const handleGo = (v: string) => {
|
||||
go(`/settings?type=${v}`);
|
||||
};
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
overlayInnerStyle={{ width: 400 }}
|
||||
title={
|
||||
<div className="awesome-tips">
|
||||
Click the button to preview, and in
|
||||
<Link to="/settings"> Settings </Link>
|
||||
you can set a single URL or Dashboard as the default window for the app.
|
||||
<br />
|
||||
<Tag onClick={() => handleGo('main_window')} color="blue">
|
||||
Main Window
|
||||
</Tag>
|
||||
{'or '}
|
||||
<Tag onClick={() => handleGo('tray_window')} color="blue">
|
||||
SystemTray Window
|
||||
</Tag>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<QuestionCircleOutlined style={{ marginLeft: 5, color: '#1677ff' }} />
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
6
src/view/dashboard/index.scss
vendored
6
src/view/dashboard/index.scss
vendored
@@ -20,7 +20,9 @@
|
||||
}
|
||||
|
||||
.txt {
|
||||
padding: 10px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
|
||||
a {
|
||||
color: #1677ff;
|
||||
@@ -37,6 +39,10 @@
|
||||
padding-top: 30px;
|
||||
}
|
||||
|
||||
&.preview {
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
.group-item {
|
||||
margin-bottom: 20px;
|
||||
|
||||
|
||||
11
src/view/dashboard/index.tsx
vendored
11
src/view/dashboard/index.tsx
vendored
@@ -1,5 +1,6 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import clsx from 'clsx';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { Row, Col, Card } from 'antd';
|
||||
import { InboxOutlined } from '@ant-design/icons';
|
||||
import { os, invoke } from '@tauri-apps/api';
|
||||
@@ -10,6 +11,7 @@ import { CHAT_AWESOME_JSON, CHAT_CONF_JSON, readJSON } from '@/utils';
|
||||
import './index.scss';
|
||||
|
||||
export default function Dashboard() {
|
||||
const [params] = useSearchParams();
|
||||
const { json } = useJson<Record<string, any>[]>(CHAT_AWESOME_JSON);
|
||||
const [list, setList] = useState<Array<[string, Record<string, any>[]]>>();
|
||||
const [hasClass, setClass] = useState(false);
|
||||
@@ -56,14 +58,19 @@ export default function Dashboard() {
|
||||
</div>
|
||||
<div className="txt">
|
||||
Go to <a onClick={() => invoke('control_window')}>{'Control Center -> Awesome'}</a> to add
|
||||
data
|
||||
data and make sure they are enabled.
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={clsx('dashboard', theme, { 'has-top-dom': hasClass })}>
|
||||
<div
|
||||
className={clsx('dashboard', theme, {
|
||||
'has-top-dom': hasClass,
|
||||
preview: params.get('type') === 'preview',
|
||||
})}
|
||||
>
|
||||
<div>
|
||||
{list.map((i) => {
|
||||
return (
|
||||
|
||||
14
src/view/settings/index.tsx
vendored
14
src/view/settings/index.tsx
vendored
@@ -1,4 +1,5 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { Form, Tabs, Space, Button, Popconfirm, message } from 'antd';
|
||||
import { invoke, dialog, process, path, shell } from '@tauri-apps/api';
|
||||
import { clone, omit, isEqual } from 'lodash';
|
||||
@@ -11,9 +12,16 @@ import MainWindow from './MainWindow';
|
||||
import TrayWindow from './TrayWindow';
|
||||
|
||||
export default function Settings() {
|
||||
const [params] = useSearchParams();
|
||||
const [activeKey, setActiveKey] = useState('general');
|
||||
const [form] = Form.useForm();
|
||||
const [chatConf, setChatConf] = useState<any>(null);
|
||||
const [filePath, setPath] = useState('');
|
||||
const key = params.get('type');
|
||||
|
||||
useEffect(() => {
|
||||
setActiveKey(key ? key : 'general');
|
||||
}, [key]);
|
||||
|
||||
useInit(async () => {
|
||||
setChatConf(await invoke('get_chat_conf'));
|
||||
@@ -55,6 +63,10 @@ export default function Settings() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleTab = (v: string) => {
|
||||
setActiveKey(v);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<FilePath paths={CHAT_CONF_JSON} />
|
||||
@@ -66,6 +78,8 @@ export default function Settings() {
|
||||
wrapperCol={{ span: 13, offset: 1 }}
|
||||
>
|
||||
<Tabs
|
||||
activeKey={activeKey}
|
||||
onChange={handleTab}
|
||||
items={[
|
||||
{ label: 'General', key: 'general', children: <General /> },
|
||||
{ label: 'Main Window', key: 'main_window', children: <MainWindow /> },
|
||||
|
||||
Reference in New Issue
Block a user