chore: add english comment
This commit is contained in:
@@ -33,6 +33,7 @@
|
|||||||
"jotai": "^2.8.4",
|
"jotai": "^2.8.4",
|
||||||
"localforage": "^1.10.0",
|
"localforage": "^1.10.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
|
"marked": "^14.1.0",
|
||||||
"numeral": "^2.0.6",
|
"numeral": "^2.0.6",
|
||||||
"query-string": "^9.0.0",
|
"query-string": "^9.0.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
@@ -42,6 +43,7 @@
|
|||||||
"umi-presets-pro": "^2.0.3"
|
"umi-presets-pro": "^2.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/marked": "^6.0.0",
|
||||||
"@types/react": "^18.3.1",
|
"@types/react": "^18.3.1",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.0",
|
||||||
"@umijs/case-sensitive-paths-webpack-plugin": "^1.0.1",
|
"@umijs/case-sensitive-paths-webpack-plugin": "^1.0.1",
|
||||||
|
|||||||
Generated
+46
-4
@@ -71,6 +71,9 @@ dependencies:
|
|||||||
lodash:
|
lodash:
|
||||||
specifier: ^4.17.21
|
specifier: ^4.17.21
|
||||||
version: 4.17.21
|
version: 4.17.21
|
||||||
|
marked:
|
||||||
|
specifier: ^14.1.0
|
||||||
|
version: 14.1.0
|
||||||
numeral:
|
numeral:
|
||||||
specifier: ^2.0.6
|
specifier: ^2.0.6
|
||||||
version: 2.0.6
|
version: 2.0.6
|
||||||
@@ -94,6 +97,9 @@ dependencies:
|
|||||||
version: 2.0.3(@babel/core@7.24.9)(@types/react-dom@18.3.0)(@types/react@18.3.1)(antd@5.18.3)(dva@2.5.0-beta.2)(rc-field-form@1.44.0)(react-dom@18.2.0)(react@18.2.0)(umi@4.3.6)
|
version: 2.0.3(@babel/core@7.24.9)(@types/react-dom@18.3.0)(@types/react@18.3.1)(antd@5.18.3)(dva@2.5.0-beta.2)(rc-field-form@1.44.0)(react-dom@18.2.0)(react@18.2.0)(umi@4.3.6)
|
||||||
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
|
'@types/marked':
|
||||||
|
specifier: ^6.0.0
|
||||||
|
version: 6.0.0
|
||||||
'@types/react':
|
'@types/react':
|
||||||
specifier: ^18.3.1
|
specifier: ^18.3.1
|
||||||
version: 18.3.1
|
version: 18.3.1
|
||||||
@@ -4459,7 +4465,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@babel/core': 7.24.5
|
'@babel/core': 7.24.5
|
||||||
postcss: 7.0.39
|
postcss: 7.0.39
|
||||||
postcss-syntax: 0.36.2(postcss@8.4.38)
|
postcss-syntax: 0.36.2(postcss@7.0.39)
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: false
|
dev: false
|
||||||
@@ -4500,7 +4506,7 @@ packages:
|
|||||||
postcss-syntax: '>=0.36.2'
|
postcss-syntax: '>=0.36.2'
|
||||||
dependencies:
|
dependencies:
|
||||||
postcss: 7.0.39
|
postcss: 7.0.39
|
||||||
postcss-syntax: 0.36.2(postcss@8.4.38)
|
postcss-syntax: 0.36.2(postcss@7.0.39)
|
||||||
remark: 13.0.0
|
remark: 13.0.0
|
||||||
unist-util-find-all-after: 3.0.2
|
unist-util-find-all-after: 3.0.2
|
||||||
transitivePeerDependencies:
|
transitivePeerDependencies:
|
||||||
@@ -4833,6 +4839,13 @@ packages:
|
|||||||
resolution: {integrity: sha512-wYCP26ZLxaT3R39kiN2+HcJ4kTd3U1waI/cY7ivWYqFP6pW3ZNpvi6Wd6PHZx7T/t8z0vlkXMg3QYLa7DZ/IJQ==}
|
resolution: {integrity: sha512-wYCP26ZLxaT3R39kiN2+HcJ4kTd3U1waI/cY7ivWYqFP6pW3ZNpvi6Wd6PHZx7T/t8z0vlkXMg3QYLa7DZ/IJQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@types/marked@6.0.0:
|
||||||
|
resolution: {integrity: sha512-jmjpa4BwUsmhxcfsgUit/7A9KbrC48Q0q8KvnY107ogcjGgTFDlIL3RpihNpx2Mu1hM4mdFQjoVc4O6JoGKHsA==, tarball: https://registry.npmjs.org/@types/marked/-/marked-6.0.0.tgz}
|
||||||
|
deprecated: This is a stub types definition. marked provides its own type definitions, so you do not need this installed.
|
||||||
|
dependencies:
|
||||||
|
marked: 14.1.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
/@types/mdast@3.0.15:
|
/@types/mdast@3.0.15:
|
||||||
resolution: {integrity: sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==, tarball: https://registry.npmjs.org/@types/mdast/-/mdast-3.0.15.tgz}
|
resolution: {integrity: sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==, tarball: https://registry.npmjs.org/@types/mdast/-/mdast-3.0.15.tgz}
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -11806,6 +11819,11 @@ packages:
|
|||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/marked@14.1.0:
|
||||||
|
resolution: {integrity: sha512-P93GikH/Pde0hM5TAXEd8I4JAYi8IB03n8qzW8Bh1BIEFpEyBoYxi/XWZA53LSpTeLBiMQOoSMj0u5E/tiVYTA==, tarball: https://registry.npmjs.org/marked/-/marked-14.1.0.tgz}
|
||||||
|
engines: {node: '>= 18'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
/mathml-tag-names@2.1.3:
|
/mathml-tag-names@2.1.3:
|
||||||
resolution: {integrity: sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==}
|
resolution: {integrity: sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==}
|
||||||
dev: false
|
dev: false
|
||||||
@@ -13125,7 +13143,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
htmlparser2: 3.10.1
|
htmlparser2: 3.10.1
|
||||||
postcss: 7.0.39
|
postcss: 7.0.39
|
||||||
postcss-syntax: 0.36.2(postcss@8.4.38)
|
postcss-syntax: 0.36.2(postcss@7.0.39)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/postcss-image-set-function@4.0.7(postcss@8.4.38):
|
/postcss-image-set-function@4.0.7(postcss@8.4.38):
|
||||||
@@ -13599,6 +13617,30 @@ packages:
|
|||||||
lodash: 4.17.21
|
lodash: 4.17.21
|
||||||
postcss: 8.4.38
|
postcss: 8.4.38
|
||||||
|
|
||||||
|
/postcss-syntax@0.36.2(postcss@7.0.39):
|
||||||
|
resolution: {integrity: sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==}
|
||||||
|
peerDependencies:
|
||||||
|
postcss: '>=5.0.0'
|
||||||
|
postcss-html: '*'
|
||||||
|
postcss-jsx: '*'
|
||||||
|
postcss-less: '*'
|
||||||
|
postcss-markdown: '*'
|
||||||
|
postcss-scss: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
postcss-html:
|
||||||
|
optional: true
|
||||||
|
postcss-jsx:
|
||||||
|
optional: true
|
||||||
|
postcss-less:
|
||||||
|
optional: true
|
||||||
|
postcss-markdown:
|
||||||
|
optional: true
|
||||||
|
postcss-scss:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
postcss: 7.0.39
|
||||||
|
dev: false
|
||||||
|
|
||||||
/postcss-syntax@0.36.2(postcss@8.4.38):
|
/postcss-syntax@0.36.2(postcss@8.4.38):
|
||||||
resolution: {integrity: sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==}
|
resolution: {integrity: sha512-nBRg/i7E3SOHWxF3PpF5WnJM/jQ1YpY9000OaVXlAQj6Zp/kIqJxEDWIZ67tAd7NLuk7zqN4yqe9nc0oNAOs1w==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -16773,7 +16815,7 @@ packages:
|
|||||||
postcss-sass: 0.4.4
|
postcss-sass: 0.4.4
|
||||||
postcss-scss: 2.1.1
|
postcss-scss: 2.1.1
|
||||||
postcss-selector-parser: 6.0.16
|
postcss-selector-parser: 6.0.16
|
||||||
postcss-syntax: 0.36.2(postcss@8.4.38)
|
postcss-syntax: 0.36.2(postcss@7.0.39)
|
||||||
postcss-value-parser: 4.2.0
|
postcss-value-parser: 4.2.0
|
||||||
resolve-from: 5.0.0
|
resolve-from: 5.0.0
|
||||||
slash: 3.0.0
|
slash: 3.0.0
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ import { RequestConfig, history } from '@umijs/max';
|
|||||||
|
|
||||||
const loginPath = '/login';
|
const loginPath = '/login';
|
||||||
|
|
||||||
// 运行时配置
|
// runtime configuration
|
||||||
export async function getInitialState(): Promise<{
|
export async function getInitialState(): Promise<{
|
||||||
fetchUserInfo: () => Promise<Global.UserInfo>;
|
fetchUserInfo: () => Promise<Global.UserInfo>;
|
||||||
currentUser?: Global.UserInfo;
|
currentUser?: Global.UserInfo;
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { marked, Tokens } from 'marked';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
interface MarkdownViewerProps {
|
||||||
|
content: string;
|
||||||
|
height?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MarkdownViewer: React.FC<MarkdownViewerProps> = ({
|
||||||
|
content,
|
||||||
|
height = 'auto'
|
||||||
|
}) => {
|
||||||
|
const renderer = new marked.Renderer();
|
||||||
|
|
||||||
|
renderer.link = ({ href, title, text }: Tokens.Link) => {
|
||||||
|
return `<a href="${href}" title="${title || ''}" target="_blank" rel="noopener noreferrer">${text}</a>`;
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ height, overflow: 'auto' }}>
|
||||||
|
<div
|
||||||
|
dangerouslySetInnerHTML={{ __html: marked(content, { renderer }) }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default React.memo(MarkdownViewer);
|
||||||
@@ -1,75 +1,27 @@
|
|||||||
import { platformCall } from '@/utils';
|
|
||||||
import { SearchOutlined } from '@ant-design/icons';
|
import { SearchOutlined } from '@ant-design/icons';
|
||||||
import { Input, Table, Tag } from 'antd';
|
import { Input, Table, Tag } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import IconFont from '../icon-font';
|
|
||||||
import './index.less';
|
import './index.less';
|
||||||
|
import KeyMapConfig from './keymap';
|
||||||
const dataSource = [
|
|
||||||
{
|
|
||||||
scope: 'playground',
|
|
||||||
command: 'New Message',
|
|
||||||
keybindingWin: 'Ctrl + N',
|
|
||||||
keybindingMac: 'N'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scope: 'models',
|
|
||||||
span: {
|
|
||||||
rowSpan: 3,
|
|
||||||
colSpan: 1
|
|
||||||
},
|
|
||||||
command: 'deploy model from Hugging Face',
|
|
||||||
keybindingWin: 'Ctrl + 1',
|
|
||||||
keybindingMac: '1'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scope: 'models',
|
|
||||||
command: 'deploy model from Ollama Library',
|
|
||||||
keybindingWin: 'Ctrl + 2',
|
|
||||||
keybindingMac: '2',
|
|
||||||
span: {
|
|
||||||
rowSpan: 0,
|
|
||||||
colSpan: 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scope: 'models',
|
|
||||||
command: '从 Hugging Face 搜索模型',
|
|
||||||
keybindingWin: 'Ctrl + K',
|
|
||||||
keybindingMac: 'K',
|
|
||||||
span: {
|
|
||||||
rowSpan: 0,
|
|
||||||
colSpan: 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const ShortCuts: React.FC<{ intl: any }> = ({ intl }) => {
|
const ShortCuts: React.FC<{ intl: any }> = ({ intl }) => {
|
||||||
const platform = platformCall();
|
const [dataList, setDataList] = React.useState<any[]>(KeyMapConfig);
|
||||||
|
|
||||||
const [dataList, setDataList] = React.useState<any[]>(dataSource);
|
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: 'Scope',
|
title: 'Scope',
|
||||||
dataIndex: 'scope',
|
dataIndex: 'scope',
|
||||||
key: 'scope',
|
key: 'scope',
|
||||||
width: 120,
|
width: 160
|
||||||
onCell: (row: any, index: number) => {
|
|
||||||
if (row.span) {
|
|
||||||
return row.span;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
rowSpan: 1,
|
|
||||||
colSpan: 1
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Command',
|
title: 'Action',
|
||||||
dataIndex: 'command',
|
dataIndex: 'command',
|
||||||
key: 'command'
|
key: 'command',
|
||||||
|
render: (text: string, row: any) => {
|
||||||
|
return <span>{intl.formatMessage({ id: text })}</span>;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Keybinding',
|
title: 'Keybinding',
|
||||||
@@ -77,21 +29,14 @@ const ShortCuts: React.FC<{ intl: any }> = ({ intl }) => {
|
|||||||
key: 'keybinding',
|
key: 'keybinding',
|
||||||
width: 180,
|
width: 180,
|
||||||
render: (text: string, row: any) => {
|
render: (text: string, row: any) => {
|
||||||
if (platform.isMac) {
|
return <Tag>{row.keybinding}</Tag>;
|
||||||
return (
|
|
||||||
<Tag>
|
|
||||||
<IconFont type="icon-command"></IconFont> + {row.keybindingMac}
|
|
||||||
</Tag>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return <Tag>{row.keybindingWin}</Tag>;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
const handleInputChange = (e: any) => {
|
const handleInputChange = (e: any) => {
|
||||||
const value = e.target.value;
|
const value = e.target.value;
|
||||||
const list = _.filter(dataSource, (item: any) => {
|
const list = _.filter(KeyMapConfig, (item: any) => {
|
||||||
return (
|
return (
|
||||||
item.command.toLowerCase().includes(value.toLowerCase()) ||
|
item.command.toLowerCase().includes(value.toLowerCase()) ||
|
||||||
item.scope.toLowerCase().includes(value.toLowerCase())
|
item.scope.toLowerCase().includes(value.toLowerCase())
|
||||||
@@ -103,10 +48,12 @@ const ShortCuts: React.FC<{ intl: any }> = ({ intl }) => {
|
|||||||
const debounceHandleInputChange = _.debounce(handleInputChange, 300);
|
const debounceHandleInputChange = _.debounce(handleInputChange, 300);
|
||||||
return (
|
return (
|
||||||
<div className="short-cuts">
|
<div className="short-cuts">
|
||||||
<h3 style={{ marginBottom: 20 }}>GPUStack 快捷方式</h3>
|
<h3 style={{ marginBottom: 20, fontWeight: 'var(--font-weight-bold)' }}>
|
||||||
|
{intl.formatMessage({ id: 'shortcuts.title' })}
|
||||||
|
</h3>
|
||||||
<Input
|
<Input
|
||||||
allowClear
|
allowClear
|
||||||
placeholder="Search keybindings"
|
placeholder={intl.formatMessage({ id: 'shortcuts.search.placeholder' })}
|
||||||
style={{ marginBottom: 16 }}
|
style={{ marginBottom: 16 }}
|
||||||
onChange={debounceHandleInputChange}
|
onChange={debounceHandleInputChange}
|
||||||
prefix={
|
prefix={
|
||||||
@@ -125,6 +72,7 @@ const ShortCuts: React.FC<{ intl: any }> = ({ intl }) => {
|
|||||||
columns={columns}
|
columns={columns}
|
||||||
dataSource={dataList}
|
dataSource={dataList}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
|
scroll={{ y: 450 }}
|
||||||
></Table>
|
></Table>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -138,7 +86,7 @@ export const modalConfig = {
|
|||||||
style: {
|
style: {
|
||||||
top: '10%'
|
top: '10%'
|
||||||
},
|
},
|
||||||
width: 660
|
width: 700
|
||||||
};
|
};
|
||||||
|
|
||||||
export default React.memo(ShortCuts);
|
export default React.memo(ShortCuts);
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import { KeyMap } from '@/config/hotkeys';
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
scope: 'playground',
|
||||||
|
command: 'shortcuts.playground.newmessage',
|
||||||
|
keybinding: KeyMap.CREATE.iconKeybinding
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scope: 'playground',
|
||||||
|
command: 'shortcuts.playground.clearmessage',
|
||||||
|
keybinding: KeyMap.CLEAR.iconKeybinding
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scope: 'playground',
|
||||||
|
command: 'shortcuts.playground.toggleparams',
|
||||||
|
keybinding: KeyMap.RIGHT.iconKeybinding
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scope: 'models',
|
||||||
|
// span: {
|
||||||
|
// rowSpan: 3,
|
||||||
|
// colSpan: 1
|
||||||
|
// },
|
||||||
|
command: 'shortcuts.models.newmodelHF',
|
||||||
|
keybinding: KeyMap.NEW1.iconKeybinding
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scope: 'models',
|
||||||
|
command: 'shortcuts.models.newmodelLM',
|
||||||
|
keybinding: KeyMap.NEW2.iconKeybinding
|
||||||
|
// span: {
|
||||||
|
// rowSpan: 0,
|
||||||
|
// colSpan: 0
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scope: 'models',
|
||||||
|
command: 'shortcuts.models.search',
|
||||||
|
keybinding: KeyMap.SEARCH.iconKeybinding
|
||||||
|
// span: {
|
||||||
|
// rowSpan: 0,
|
||||||
|
// colSpan: 0
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scope: 'resources',
|
||||||
|
command: 'shortcuts.resources.addworker',
|
||||||
|
keybinding: KeyMap.CREATE.iconKeybinding
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scope: 'API keys',
|
||||||
|
command: 'shortcuts.apikeys.new',
|
||||||
|
keybinding: KeyMap.CREATE.iconKeybinding
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scope: 'users',
|
||||||
|
command: 'shortcuts.users.new',
|
||||||
|
keybinding: KeyMap.CREATE.iconKeybinding
|
||||||
|
}
|
||||||
|
];
|
||||||
+55
-12
@@ -1,17 +1,60 @@
|
|||||||
export default {
|
import { platformCall } from '@/utils';
|
||||||
CREATE: ['ctrl+alt+n', 'option+meta+n'],
|
const platform = platformCall();
|
||||||
SAVE: ['ctrl+s', 'meta+s'],
|
const KeybindingsMap = {
|
||||||
|
CREATE: ['alt+ctrl+N', 'alt+meta+N'],
|
||||||
|
CLEAR: ['alt+ctrl+W', 'alt+meta+W'],
|
||||||
|
RIGHT: ['ctrl+RIGHT', 'meta+RIGHT'],
|
||||||
|
SAVE: ['ctrl+S', 'meta+S'],
|
||||||
SUBMIT: ['ctrl+enter', 'meta+enter'],
|
SUBMIT: ['ctrl+enter', 'meta+enter'],
|
||||||
SAVEAS: ['ctrl+shift+s', 'meta+shift+s'],
|
SAVEAS: ['alt+ctrl+S', 'alt+meta+S'],
|
||||||
OPEN: ['ctrl+o', 'meta+o'],
|
OPEN: ['alt+ctrl+O', 'alt+meta+O'],
|
||||||
CANCEL: ['ctrl+w', 'meta+w'],
|
CANCEL: ['ctrl+W', 'meta+W'],
|
||||||
DELETE: ['delete'],
|
DELETE: ['delete'],
|
||||||
COPY: ['ctrl+c', 'meta+c'],
|
COPY: ['ctrl+C', 'meta+C'],
|
||||||
REFRESH: ['ctrl+r', 'meta+r'],
|
REFRESH: ['ctrl+R', 'meta+R'],
|
||||||
EDIT: ['ctrl+e', 'meta+e'],
|
EDIT: ['ctrl+E', 'meta+E'],
|
||||||
SEARCH: ['ctrl+f', 'meta+f'],
|
SEARCH: ['ctrl+K', 'meta+K'],
|
||||||
RESET: ['ctrl+shift+r', 'meta+shift+r'],
|
RESET: ['alt+ctrl+R', 'alt+meta+R'],
|
||||||
INPUT: ['ctrl+k', 'meta+k'],
|
INPUT: ['ctrl+K', 'meta+K'],
|
||||||
NEW1: ['ctrl+1', 'meta+1'],
|
NEW1: ['ctrl+1', 'meta+1'],
|
||||||
NEW2: ['ctrl+2', 'meta+2']
|
NEW2: ['ctrl+2', 'meta+2']
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type KeyBindingType = keyof typeof KeybindingsMap;
|
||||||
|
|
||||||
|
type KeybindingValue = {
|
||||||
|
keybinding: string;
|
||||||
|
command: KeyBindingType;
|
||||||
|
textKeybinding: string;
|
||||||
|
iconKeybinding: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const KeybiningList: KeybindingValue[] = Object.entries(KeybindingsMap).map(
|
||||||
|
([key, value]) => {
|
||||||
|
const keybinding = platform.isMac ? value[1] || value[0] : value[0];
|
||||||
|
return {
|
||||||
|
keybinding: keybinding,
|
||||||
|
command: key,
|
||||||
|
textKeybinding: platform.isMac
|
||||||
|
? keybinding.replace('meta', 'Command').replace('alt', 'Option')
|
||||||
|
: keybinding.replace('ctrl', 'Ctrl'),
|
||||||
|
iconKeybinding: platform.isMac
|
||||||
|
? keybinding.replace('meta', '⌘').replace('alt', '⌥')
|
||||||
|
: keybinding.replace('ctrl', 'Ctrl')
|
||||||
|
} as KeybindingValue;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const KeyMap: Record<KeyBindingType, KeybindingValue> = KeybiningList.reduce(
|
||||||
|
(acc: any, item) => {
|
||||||
|
acc[item.command] = item;
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log('KeyMap=========', KeyMap);
|
||||||
|
|
||||||
|
export { KeyMap, KeybiningList };
|
||||||
|
|
||||||
|
export default KeybindingsMap;
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
// 应用前置、全局运行的逻辑时 会在这里执行
|
// Logic that runs globally and before the application will be executed here
|
||||||
|
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import localizedFormat from 'dayjs/plugin/localizedFormat';
|
import localizedFormat from 'dayjs/plugin/localizedFormat';
|
||||||
|
|||||||
+15
-4
@@ -1,23 +1,27 @@
|
|||||||
@media screen and (max-width: 480px) {
|
@media screen and (max-width: 480px) {
|
||||||
/* 在小屏幕的时候可以有更好的体验 */
|
|
||||||
.umi-plugin-layout-container {
|
.umi-plugin-layout-container {
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.umi-plugin-layout-container > * {
|
.umi-plugin-layout-container > * {
|
||||||
border-radius: 0 !important;
|
border-radius: 0 !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.umi-plugin-layout-menu .anticon {
|
.umi-plugin-layout-menu .anticon {
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.umi-plugin-layout-menu .ant-dropdown-menu-item {
|
.umi-plugin-layout-menu .ant-dropdown-menu-item {
|
||||||
min-width: 160px;
|
min-width: 160px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.umi-plugin-layout-right {
|
.umi-plugin-layout-right {
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.umi-plugin-layout-right .umi-plugin-layout-action {
|
.umi-plugin-layout-right .umi-plugin-layout-action {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -26,25 +30,32 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.umi-plugin-layout-right .umi-plugin-layout-action > i {
|
.umi-plugin-layout-right .umi-plugin-layout-action > i {
|
||||||
color: rgba(255, 255, 255, 0.85);
|
color: rgba(255, 255, 255, 85%);
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
.umi-plugin-layout-right .umi-plugin-layout-action:hover {
|
.umi-plugin-layout-right .umi-plugin-layout-action:hover {
|
||||||
background: rgba(0, 0, 0, 0.025);
|
background: rgba(0, 0, 0, 2.5%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.umi-plugin-layout-right .umi-plugin-layout-action.opened {
|
.umi-plugin-layout-right .umi-plugin-layout-action.opened {
|
||||||
background: rgba(0, 0, 0, 0.025);
|
background: rgba(0, 0, 0, 2.5%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.umi-plugin-layout-right .umi-plugin-layout-search {
|
.umi-plugin-layout-right .umi-plugin-layout-search {
|
||||||
padding: 0 12px;
|
padding: 0 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.umi-plugin-layout-right .umi-plugin-layout-search:hover {
|
.umi-plugin-layout-right .umi-plugin-layout-search:hover {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.umi-plugin-layout-name {
|
.umi-plugin-layout-name {
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.umi-plugin-layout-name.umi-plugin-layout-hide-avatar-img {
|
.umi-plugin-layout-name.umi-plugin-layout-hide-avatar-img {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
// This file is generated by Umi automatically
|
|
||||||
// DO NOT CHANGE IT MANUALLY!
|
|
||||||
import GpustackLogo from '@/assets/images/gpustack-logo.png';
|
import GpustackLogo from '@/assets/images/gpustack-logo.png';
|
||||||
import SmallLogo from '@/assets/images/small-logo-200x200.png';
|
import SmallLogo from '@/assets/images/small-logo-200x200.png';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ type InitialStateType = {
|
|||||||
currentUser?: Global.UserInfo;
|
currentUser?: Global.UserInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 过滤出需要显示的路由, 这里的filterFn 指 不希望显示的层级
|
// Filter out the routes that need to be displayed, where filterFn indicates the levels that should not be shown
|
||||||
const filterRoutes = (
|
const filterRoutes = (
|
||||||
routes: IRoute[],
|
routes: IRoute[],
|
||||||
filterFn: (route: IRoute) => boolean
|
filterFn: (route: IRoute) => boolean
|
||||||
@@ -99,8 +99,6 @@ export default (props: any) => {
|
|||||||
setInitialState: null
|
setInitialState: null
|
||||||
};
|
};
|
||||||
|
|
||||||
// initialState: InitialStateType
|
|
||||||
|
|
||||||
const { initialState, loading, setInitialState } = initialInfo;
|
const { initialState, loading, setInitialState } = initialInfo;
|
||||||
|
|
||||||
const userConfig = {
|
const userConfig = {
|
||||||
@@ -189,6 +187,8 @@ export default (props: any) => {
|
|||||||
const { location } = history;
|
const { location } = history;
|
||||||
|
|
||||||
console.log('onPageChange', userInfo, initialState);
|
console.log('onPageChange', userInfo, initialState);
|
||||||
|
|
||||||
|
// if user is not change password, redirect to change password page
|
||||||
if (
|
if (
|
||||||
location.pathname !== loginPath &&
|
location.pathname !== loginPath &&
|
||||||
userInfo?.require_password_change
|
userInfo?.require_password_change
|
||||||
@@ -198,8 +198,7 @@ export default (props: any) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果没有登录,重定向到 login
|
// if user is not logged in, redirect to login page
|
||||||
|
|
||||||
if (!initialState?.currentUser && location.pathname !== loginPath) {
|
if (!initialState?.currentUser && location.pathname !== loginPath) {
|
||||||
history.push(loginPath);
|
history.push(loginPath);
|
||||||
} else if (location.pathname === '/') {
|
} else if (location.pathname === '/') {
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
// This file is generated by Umi automatically
|
|
||||||
// DO NOT CHANGE IT MANUALLY!
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import icons from './icons';
|
import icons from './icons';
|
||||||
|
|
||||||
@@ -13,7 +11,6 @@ function formatIcon(name: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function patchRoutes({ routes, initialState }) {
|
export function patchRoutes({ routes, initialState }) {
|
||||||
console.log('patchRoutes99999', routes);
|
|
||||||
Object.keys(routes).forEach((key) => {
|
Object.keys(routes).forEach((key) => {
|
||||||
const { icon } = routes[key];
|
const { icon } = routes[key];
|
||||||
if (icon && typeof icon === 'string') {
|
if (icon && typeof icon === 'string') {
|
||||||
|
|||||||
Vendored
-2
@@ -1,5 +1,3 @@
|
|||||||
// This file is generated by Umi automatically
|
|
||||||
// DO NOT CHANGE IT MANUALLY!
|
|
||||||
import type { RunTimeLayoutConfig } from './types';
|
import type { RunTimeLayoutConfig } from './types';
|
||||||
export interface IRuntimeConfig {
|
export interface IRuntimeConfig {
|
||||||
layout?: RunTimeLayoutConfig;
|
layout?: RunTimeLayoutConfig;
|
||||||
|
|||||||
Vendored
+3
-6
@@ -1,8 +1,5 @@
|
|||||||
// This file is generated by Umi automatically
|
|
||||||
// DO NOT CHANGE IT MANUALLY!
|
|
||||||
/// <reference types="@ant-design/pro-components" />
|
|
||||||
|
|
||||||
import type InitialStateType from '@@/plugin-initialState/@@initialState';
|
import type InitialStateType from '@@/plugin-initialState/@@initialState';
|
||||||
|
import '@ant-design/pro-components';
|
||||||
import type { HeaderProps, ProLayoutProps } from '@ant-design/pro-components';
|
import type { HeaderProps, ProLayoutProps } from '@ant-design/pro-components';
|
||||||
type InitDataType = ReturnType<typeof InitialStateType>;
|
type InitDataType = ReturnType<typeof InitialStateType>;
|
||||||
|
|
||||||
@@ -26,12 +23,12 @@ export type RunTimeLayoutConfig = (initData: InitDataType) => Omit<
|
|||||||
loading: InitDataType['loading'];
|
loading: InitDataType['loading'];
|
||||||
initialState: InitDataType['initialState'];
|
initialState: InitDataType['initialState'];
|
||||||
setInitialState: InitDataType['setInitialState'];
|
setInitialState: InitDataType['setInitialState'];
|
||||||
},
|
}
|
||||||
) => JSX.Element)
|
) => JSX.Element)
|
||||||
| false;
|
| false;
|
||||||
rightRender?: (
|
rightRender?: (
|
||||||
initialState: InitDataType['initialState'],
|
initialState: InitDataType['initialState'],
|
||||||
setInitialState: InitDataType['setInitialState'],
|
setInitialState: InitDataType['setInitialState'],
|
||||||
runtimeConfig: RunTimeLayoutConfig,
|
runtimeConfig: RunTimeLayoutConfig
|
||||||
) => JSX.Element;
|
) => JSX.Element;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import menu from './en-US/menu';
|
|||||||
import models from './en-US/models';
|
import models from './en-US/models';
|
||||||
import playground from './en-US/playground';
|
import playground from './en-US/playground';
|
||||||
import resources from './en-US/resources';
|
import resources from './en-US/resources';
|
||||||
|
import shortcuts from './en-US/shortcuts';
|
||||||
import usage from './en-US/usage';
|
import usage from './en-US/usage';
|
||||||
import users from './en-US/users';
|
import users from './en-US/users';
|
||||||
|
|
||||||
@@ -17,5 +18,6 @@ export default {
|
|||||||
...apikeys,
|
...apikeys,
|
||||||
...users,
|
...users,
|
||||||
...dashboard,
|
...dashboard,
|
||||||
...usage
|
...usage,
|
||||||
|
...shortcuts
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
export default {
|
||||||
|
'shortcuts.search.placeholder': 'Search keybindings',
|
||||||
|
'shortcuts.title': 'Keyboard shortcuts',
|
||||||
|
'shortcuts.playground.newmessage': 'New message',
|
||||||
|
'shortcuts.playground.clearmessage': 'Clear messages',
|
||||||
|
'shortcuts.playground.toggleparams': 'Collapse/Expand parameters',
|
||||||
|
'shortcuts.models.newmodelHF': 'Deploy Hugging Face model',
|
||||||
|
'shortcuts.models.newmodelLM': 'Deploy Ollama model',
|
||||||
|
'shortcuts.models.search': 'Search models from Hugging Face',
|
||||||
|
'shortcuts.resources.addworker': 'Add worker',
|
||||||
|
'shortcuts.apikeys.new': 'New API key',
|
||||||
|
'shortcuts.users.new': 'New user'
|
||||||
|
};
|
||||||
@@ -5,6 +5,7 @@ import menu from './zh-CN/menu';
|
|||||||
import models from './zh-CN/models';
|
import models from './zh-CN/models';
|
||||||
import playground from './zh-CN/playground';
|
import playground from './zh-CN/playground';
|
||||||
import resources from './zh-CN/resources';
|
import resources from './zh-CN/resources';
|
||||||
|
import shortcuts from './zh-CN/shortcuts';
|
||||||
import usage from './zh-CN/usage';
|
import usage from './zh-CN/usage';
|
||||||
import users from './zh-CN/users';
|
import users from './zh-CN/users';
|
||||||
|
|
||||||
@@ -17,5 +18,6 @@ export default {
|
|||||||
...apikeys,
|
...apikeys,
|
||||||
...users,
|
...users,
|
||||||
...dashboard,
|
...dashboard,
|
||||||
...usage
|
...usage,
|
||||||
|
...shortcuts
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// keyborad shortcuts
|
||||||
|
export default {
|
||||||
|
'shortcuts.title': '快捷键',
|
||||||
|
'shortcuts.search.placeholder': '搜索快捷键',
|
||||||
|
'shortcuts.playground.newmessage': '新建消息',
|
||||||
|
'shortcuts.playground.clearmessage': '清空消息',
|
||||||
|
'shortcuts.playground.toggleparams': '收起/展开参数',
|
||||||
|
'shortcuts.models.newmodelHF': '部署 Hugging Face 模型',
|
||||||
|
'shortcuts.models.newmodelLM': '部署 Ollama 模型',
|
||||||
|
'shortcuts.models.search': '从 Hugging Face 搜索模型',
|
||||||
|
'shortcuts.resources.addworker': '添加节点',
|
||||||
|
'shortcuts.apikeys.new': '新建 API 密钥',
|
||||||
|
'shortcuts.users.new': '新建用户'
|
||||||
|
};
|
||||||
@@ -8,11 +8,11 @@ const AccessPage: React.FC = () => {
|
|||||||
<PageContainer
|
<PageContainer
|
||||||
ghost
|
ghost
|
||||||
header={{
|
header={{
|
||||||
title: '权限示例'
|
title: 'permission example'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Access accessible={access.canSeeAdmin}>
|
<Access accessible={access.canSeeAdmin}>
|
||||||
<Button>只有 Admin 可以看到这个按钮</Button>
|
<Button>Only Admin can see this button</Button>
|
||||||
</Access>
|
</Access>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import DeleteModal from '@/components/delete-modal';
|
import DeleteModal from '@/components/delete-modal';
|
||||||
import PageTools from '@/components/page-tools';
|
import PageTools from '@/components/page-tools';
|
||||||
import { PageAction } from '@/config';
|
import { PageAction } from '@/config';
|
||||||
|
import HotKeys from '@/config/hotkeys';
|
||||||
import type { PageActionType } from '@/config/types';
|
import type { PageActionType } from '@/config/types';
|
||||||
import useTableRowSelection from '@/hooks/use-table-row-selection';
|
import useTableRowSelection from '@/hooks/use-table-row-selection';
|
||||||
import useTableSort from '@/hooks/use-table-sort';
|
import useTableSort from '@/hooks/use-table-sort';
|
||||||
@@ -12,6 +13,7 @@ import { Button, Input, Space, Table, Tooltip } from 'antd';
|
|||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { deleteApisKey, queryApisKeysList } from './apis';
|
import { deleteApisKey, queryApisKeysList } from './apis';
|
||||||
import AddAPIKeyModal from './components/add-apikey';
|
import AddAPIKeyModal from './components/add-apikey';
|
||||||
import { ListItem } from './config/types';
|
import { ListItem } from './config/types';
|
||||||
@@ -140,6 +142,16 @@ const APIKeys: React.FC = () => {
|
|||||||
fetchData();
|
fetchData();
|
||||||
}, [queryParams]);
|
}, [queryParams]);
|
||||||
|
|
||||||
|
useHotkeys(
|
||||||
|
HotKeys.CREATE,
|
||||||
|
() => {
|
||||||
|
handleAddUser();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
enabled: !openAddModal
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageContainer
|
<PageContainer
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import hotkeys from '@/config/hotkeys';
|
import hotkeys from '@/config/hotkeys';
|
||||||
import { platformCall } from '@/utils';
|
|
||||||
import { SearchOutlined } from '@ant-design/icons';
|
import { SearchOutlined } from '@ant-design/icons';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Input } from 'antd';
|
import { Input } from 'antd';
|
||||||
@@ -13,7 +12,6 @@ const SearchInput: React.FC<{
|
|||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [isFocus, setIsFocus] = useState(false);
|
const [isFocus, setIsFocus] = useState(false);
|
||||||
const inputRef = useRef<any>(null);
|
const inputRef = useRef<any>(null);
|
||||||
const platform = platformCall();
|
|
||||||
|
|
||||||
useHotkeys(hotkeys.INPUT.join(','), () => {
|
useHotkeys(hotkeys.INPUT.join(','), () => {
|
||||||
inputRef.current?.focus?.();
|
inputRef.current?.focus?.();
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ const Separator: React.FC = () => {
|
|||||||
style={{ height: 'calc(100vh - 89px)', marginInline: '0px' }}
|
style={{ height: 'calc(100vh - 89px)', marginInline: '0px' }}
|
||||||
></Divider>
|
></Divider>
|
||||||
<span className="shape"></span>
|
<span className="shape"></span>
|
||||||
{/* <span className="shape-s"></span> */}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
.shape {
|
.shape {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
border-radius: 0 2px 0 0;
|
||||||
top: 10px;
|
top: 10px;
|
||||||
left: -10px;
|
left: -10px;
|
||||||
width: 22px;
|
width: 22px;
|
||||||
@@ -14,15 +15,4 @@
|
|||||||
background-color: var(--color-white-1);
|
background-color: var(--color-white-1);
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
.shape-s {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 4px;
|
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
border: 16px solid transparent;
|
|
||||||
border-left: 16px solid var(--color-fill-sider);
|
|
||||||
z-index: 100;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -239,6 +239,30 @@ const MessageList: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useHotkeys(
|
||||||
|
HotKeys.CREATE.join(','),
|
||||||
|
() => {
|
||||||
|
handleNewMessage();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
enabled: !loading,
|
||||||
|
enableOnFormTags: !loading,
|
||||||
|
preventDefault: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
useHotkeys(
|
||||||
|
HotKeys.CLEAR.join(','),
|
||||||
|
() => {
|
||||||
|
handleClear();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
enabled: !loading,
|
||||||
|
enableOnFormTags: !loading,
|
||||||
|
preventDefault: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="ground-left">
|
<div className="ground-left">
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import IconFont from '@/components/icon-font';
|
import IconFont from '@/components/icon-font';
|
||||||
|
import HotKeys from '@/config/hotkeys';
|
||||||
import { PageContainer } from '@ant-design/pro-components';
|
import { PageContainer } from '@ant-design/pro-components';
|
||||||
import { useIntl, useSearchParams } from '@umijs/max';
|
import { useIntl, useSearchParams } from '@umijs/max';
|
||||||
import { Button, Divider, Space } from 'antd';
|
import { Button, Divider, Space } from 'antd';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { useRef, useState } from 'react';
|
import { useRef, useState } from 'react';
|
||||||
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import GroundLeft from './components/ground-left';
|
import GroundLeft from './components/ground-left';
|
||||||
import ParamsSettings from './components/params-settings';
|
import ParamsSettings from './components/params-settings';
|
||||||
import './style/play-ground.less';
|
import './style/play-ground.less';
|
||||||
@@ -20,6 +22,18 @@ const Playground: React.FC = () => {
|
|||||||
groundLeftRef.current?.viewCode?.();
|
groundLeftRef.current?.viewCode?.();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useHotkeys(
|
||||||
|
HotKeys.RIGHT.join(','),
|
||||||
|
() => {
|
||||||
|
setCollapse((pre) => {
|
||||||
|
return !pre;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
{
|
||||||
|
preventDefault: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContainer
|
<PageContainer
|
||||||
ghost
|
ghost
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import DeleteModal from '@/components/delete-modal';
|
|||||||
import PageTools from '@/components/page-tools';
|
import PageTools from '@/components/page-tools';
|
||||||
import ProgressBar from '@/components/progress-bar';
|
import ProgressBar from '@/components/progress-bar';
|
||||||
import StatusTag from '@/components/status-tag';
|
import StatusTag from '@/components/status-tag';
|
||||||
|
import Hotkeys from '@/config/hotkeys';
|
||||||
import useTableRowSelection from '@/hooks/use-table-row-selection';
|
import useTableRowSelection from '@/hooks/use-table-row-selection';
|
||||||
import useTableSort from '@/hooks/use-table-sort';
|
import useTableSort from '@/hooks/use-table-sort';
|
||||||
import { convertFileSize, handleBatchRequest } from '@/utils';
|
import { convertFileSize, handleBatchRequest } from '@/utils';
|
||||||
@@ -15,6 +16,7 @@ import { useIntl } from '@umijs/max';
|
|||||||
import { Button, Input, Space, Table, Tooltip } from 'antd';
|
import { Button, Input, Space, Table, Tooltip } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { memo, useCallback, useEffect, useRef, useState } from 'react';
|
import { memo, useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { deleteWorker, queryWorkersList } from '../apis';
|
import { deleteWorker, queryWorkersList } from '../apis';
|
||||||
import { WorkerStatusMapValue, status } from '../config';
|
import { WorkerStatusMapValue, status } from '../config';
|
||||||
import { Filesystem, GPUDeviceItem, ListItem } from '../config/types';
|
import { Filesystem, GPUDeviceItem, ListItem } from '../config/types';
|
||||||
@@ -166,6 +168,10 @@ const Resources: React.FC = () => {
|
|||||||
fetchData();
|
fetchData();
|
||||||
}, [queryParams]);
|
}, [queryParams]);
|
||||||
|
|
||||||
|
useHotkeys(Hotkeys.CREATE.join(','), handleAddWorker, {
|
||||||
|
enabled: !open
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageTools
|
<PageTools
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import DeleteModal from '@/components/delete-modal';
|
|||||||
import DropdownButtons from '@/components/drop-down-buttons';
|
import DropdownButtons from '@/components/drop-down-buttons';
|
||||||
import PageTools from '@/components/page-tools';
|
import PageTools from '@/components/page-tools';
|
||||||
import { PageAction } from '@/config';
|
import { PageAction } from '@/config';
|
||||||
|
import HotKeys from '@/config/hotkeys';
|
||||||
import type { PageActionType } from '@/config/types';
|
import type { PageActionType } from '@/config/types';
|
||||||
import useTableRowSelection from '@/hooks/use-table-row-selection';
|
import useTableRowSelection from '@/hooks/use-table-row-selection';
|
||||||
import useTableSort from '@/hooks/use-table-sort';
|
import useTableSort from '@/hooks/use-table-sort';
|
||||||
@@ -20,6 +21,7 @@ import { Button, Input, Space, Table, message } from 'antd';
|
|||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { useEffect, useRef, useState } from 'react';
|
import { useEffect, useRef, useState } from 'react';
|
||||||
|
import { useHotkeys } from 'react-hotkeys-hook';
|
||||||
import { createUser, deleteUser, queryUsersList, updateUser } from './apis';
|
import { createUser, deleteUser, queryUsersList, updateUser } from './apis';
|
||||||
import AddModal from './components/add-modal';
|
import AddModal from './components/add-modal';
|
||||||
import { FormData, ListItem } from './config/types';
|
import { FormData, ListItem } from './config/types';
|
||||||
@@ -197,6 +199,16 @@ const Users: React.FC = () => {
|
|||||||
fetchData();
|
fetchData();
|
||||||
}, [queryParams]);
|
}, [queryParams]);
|
||||||
|
|
||||||
|
useHotkeys(
|
||||||
|
HotKeys.CREATE,
|
||||||
|
() => {
|
||||||
|
handleAddUser();
|
||||||
|
},
|
||||||
|
{
|
||||||
|
enabled: !openAddModal
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<PageContainer
|
<PageContainer
|
||||||
|
|||||||
+18
-19
@@ -48,9 +48,8 @@ export const generateRandomArray = (config?: {
|
|||||||
let prevValue = Math.floor(Math.random() * (max - min + 1)) + min;
|
let prevValue = Math.floor(Math.random() * (max - min + 1)) + min;
|
||||||
|
|
||||||
for (let i = 0; i < length; i++) {
|
for (let i = 0; i < length; i++) {
|
||||||
// 确保波动不太大
|
let newValue = prevValue + Math.floor(Math.random() * 21) - offset; // Fluctuation range [-10, 10]
|
||||||
let newValue = prevValue + Math.floor(Math.random() * 21) - offset; // 波动范围 [-10, 10]
|
newValue = Math.max(min, Math.min(max, newValue)); // Ensure within [10, 100]
|
||||||
newValue = Math.max(min, Math.min(max, newValue)); // 保证在 [10, 100] 范围内
|
|
||||||
data.push(newValue);
|
data.push(newValue);
|
||||||
prevValue = newValue;
|
prevValue = newValue;
|
||||||
}
|
}
|
||||||
@@ -68,15 +67,15 @@ export const generateFluctuatingData2 = ({
|
|||||||
const y = [];
|
const y = [];
|
||||||
|
|
||||||
for (let i = 0; i < total; i++) {
|
for (let i = 0; i < total; i++) {
|
||||||
// 生成一个基本的线性趋势,使用正弦函数
|
// Generate a basic linear trend using a sine function
|
||||||
const phaseShift = Math.random() * 2 * Math.PI;
|
const phaseShift = Math.random() * 2 * Math.PI;
|
||||||
const trend =
|
const trend =
|
||||||
max * Math.sin((3 * Math.PI * i + phaseShift) / total) + max / 2;
|
max * Math.sin((3 * Math.PI * i + phaseShift) / total) + max / 2;
|
||||||
|
|
||||||
// 生成噪声
|
// Generate noise
|
||||||
const noise = (Math.random() * 2 - 1) * noiseLevel;
|
const noise = (Math.random() * 2 - 1) * noiseLevel;
|
||||||
|
|
||||||
// 叠加趋势和噪声
|
// Add trend and noise
|
||||||
const value = trend + noise;
|
const value = trend + noise;
|
||||||
x.push(i);
|
x.push(i);
|
||||||
y.push(Math.max(min, value));
|
y.push(Math.max(min, value));
|
||||||
@@ -94,19 +93,19 @@ export const generateFluctuatingData = ({
|
|||||||
min = 0
|
min = 0
|
||||||
}) => {
|
}) => {
|
||||||
/**
|
/**
|
||||||
* 生成一组用于折线图的数据,具有自然且美观的趋势。
|
* Generate a set of data for a line chart with a natural and aesthetically pleasing trend.
|
||||||
*
|
*
|
||||||
* 参数:
|
* Parameters:
|
||||||
* total (number): 生成数据点的数量
|
* total (number): Number of data points to generate
|
||||||
* trendType (string): 数据趋势类型, 可选'linear', 'sine', 'exponential'
|
* trendType (string): Type of data trend, options are 'linear', 'sine', 'exponential'
|
||||||
* max (number): 波动幅度
|
* max (number): Fluctuation amplitude
|
||||||
* f (number): 波动频率
|
* f (number): Fluctuation frequency
|
||||||
* phase (number): 波动相位
|
* phase (number): Fluctuation phase
|
||||||
* min (number): 数据的最小值
|
* min (number): Minimum value of the data
|
||||||
*
|
*
|
||||||
* 返回:
|
* Returns:
|
||||||
* x (number[]): x轴数据
|
* x (number[]): x-axis data
|
||||||
* y (number[]): y轴数据
|
* y (number[]): y-axis data
|
||||||
*/
|
*/
|
||||||
const x = Array.from({ length: total }, (_, i) => (i * 10) / (total - 1));
|
const x = Array.from({ length: total }, (_, i) => (i * 10) / (total - 1));
|
||||||
|
|
||||||
@@ -131,11 +130,11 @@ export const generateFluctuatingData = ({
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'无效的trendType参数,请选择"linear", "sine"或"exponential".'
|
'Invalid trendType parameter. Please choose "linear", "sine", or "exponential".'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将数据调整到最小值
|
// Adjust the data to the minimum value
|
||||||
const minY = Math.min(...y);
|
const minY = Math.min(...y);
|
||||||
y = y.map((val) => _.round(val - minY + min, 2));
|
y = y.map((val) => _.round(val - minY + min, 2));
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user