build: sync config
This commit is contained in:
@@ -19,6 +19,9 @@ export default defineConfig({
|
|||||||
history: {
|
history: {
|
||||||
type: 'hash'
|
type: 'hash'
|
||||||
},
|
},
|
||||||
|
define: {
|
||||||
|
'process.env.ENABLE_ENTERPRISE': process.env.ENABLE_ENTERPRISE
|
||||||
|
},
|
||||||
analyze: {
|
analyze: {
|
||||||
analyzerMode: 'server',
|
analyzerMode: 'server',
|
||||||
analyzerPort: 8888,
|
analyzerPort: 8888,
|
||||||
|
|||||||
@@ -302,6 +302,26 @@ export default [
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'apikeys',
|
||||||
|
path: '/api-keys',
|
||||||
|
key: 'apikeys',
|
||||||
|
hideInMenu: true,
|
||||||
|
selectedIcon: 'icon-key-filled',
|
||||||
|
icon: 'icon-key',
|
||||||
|
defaultIcon: 'icon-key',
|
||||||
|
component: './api-keys'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'settings',
|
||||||
|
path: '/settings',
|
||||||
|
key: 'settings',
|
||||||
|
hideInMenu: true,
|
||||||
|
selectedIcon: 'icon-settings-filled',
|
||||||
|
icon: 'icon-settings',
|
||||||
|
defaultIcon: 'icon-settings',
|
||||||
|
component: './settings'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'profile',
|
name: 'profile',
|
||||||
path: '/profile',
|
path: '/profile',
|
||||||
|
|||||||
@@ -3,13 +3,19 @@
|
|||||||
"author": "jialin",
|
"author": "jialin",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "max build",
|
"build": "max build",
|
||||||
|
"build:enterprise": "node ./scripts/run-enterprise-build.cjs",
|
||||||
"check:locales": "npx tsx ./src/locales/check.ts",
|
"check:locales": "npx tsx ./src/locales/check.ts",
|
||||||
"dev": "max dev",
|
"dev": "max dev",
|
||||||
|
"dev:enterprise": "node ./scripts/run-enterprise-dev.cjs",
|
||||||
"format": "prettier --cache --write .",
|
"format": "prettier --cache --write .",
|
||||||
"postinstall": "max setup",
|
"postinstall": "max setup",
|
||||||
"prepare": "husky",
|
"prepare": "husky",
|
||||||
"preview": "max preview",
|
"preview": "max preview",
|
||||||
"setup": "max setup",
|
"setup": "max setup",
|
||||||
|
"sync:enterprise-config:clean": "node ./scripts/sync-enterprise-config.cjs clean",
|
||||||
|
"sync:enterprise-config": "node ./scripts/sync-enterprise-config.cjs",
|
||||||
|
"sync:enterprise-global:clean": "npm run sync:enterprise-config:clean",
|
||||||
|
"sync:enterprise-global": "npm run sync:enterprise-config",
|
||||||
"start": "npm run dev"
|
"start": "npm run dev"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -94,6 +100,7 @@
|
|||||||
"babel-plugin-named-asset-import": "^0.3.8",
|
"babel-plugin-named-asset-import": "^0.3.8",
|
||||||
"case-sensitive-paths-webpack-plugin": "^2.4.0",
|
"case-sensitive-paths-webpack-plugin": "^2.4.0",
|
||||||
"compression-webpack-plugin": "^11.1.0",
|
"compression-webpack-plugin": "^11.1.0",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
"css-loader": "^7.1.2",
|
"css-loader": "^7.1.2",
|
||||||
"eslint": "^9.39.4",
|
"eslint": "^9.39.4",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
const { spawnSync } = require('node:child_process');
|
||||||
|
const path = require('node:path');
|
||||||
|
|
||||||
|
const syncScript = path.resolve(__dirname, './sync-enterprise-config.cjs');
|
||||||
|
|
||||||
|
const runNodeScript = (args) => {
|
||||||
|
const result = spawnSync(process.execPath, [syncScript, ...args], {
|
||||||
|
stdio: 'inherit'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.error) {
|
||||||
|
throw result.error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof result.status === 'number' && result.status !== 0) {
|
||||||
|
process.exit(result.status);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const runBuild = () =>
|
||||||
|
spawnSync('max', ['build'], {
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
ENABLE_ENTERPRISE: 'true'
|
||||||
|
},
|
||||||
|
shell: true,
|
||||||
|
stdio: 'inherit'
|
||||||
|
});
|
||||||
|
|
||||||
|
let buildResult;
|
||||||
|
|
||||||
|
try {
|
||||||
|
runNodeScript([]);
|
||||||
|
buildResult = runBuild();
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
runNodeScript(['clean']);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to clean enterprise config:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buildResult?.error) {
|
||||||
|
throw buildResult.error;
|
||||||
|
}
|
||||||
|
|
||||||
|
process.exit(buildResult?.status ?? 0);
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
const { spawn, spawnSync } = require('node:child_process');
|
||||||
|
const path = require('node:path');
|
||||||
|
|
||||||
|
const syncScript = path.resolve(__dirname, './sync-enterprise-config.cjs');
|
||||||
|
|
||||||
|
const runNodeScript = (args) => {
|
||||||
|
const result = spawnSync(process.execPath, [syncScript, ...args], {
|
||||||
|
stdio: 'inherit'
|
||||||
|
});
|
||||||
|
|
||||||
|
if (typeof result.status === 'number' && result.status !== 0) {
|
||||||
|
process.exit(result.status);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.error) {
|
||||||
|
throw result.error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
runNodeScript([]);
|
||||||
|
|
||||||
|
const child = spawn('max', ['dev'], {
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
ENABLE_ENTERPRISE: 'true'
|
||||||
|
},
|
||||||
|
shell: true,
|
||||||
|
stdio: 'inherit'
|
||||||
|
});
|
||||||
|
|
||||||
|
let cleaned = false;
|
||||||
|
|
||||||
|
const clean = () => {
|
||||||
|
if (cleaned) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cleaned = true;
|
||||||
|
try {
|
||||||
|
runNodeScript(['clean']);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to clean enterprise config:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const forwardSignal = (signal) => {
|
||||||
|
if (!child.killed) {
|
||||||
|
child.kill(signal);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
['SIGINT', 'SIGTERM', 'SIGHUP'].forEach((signal) => {
|
||||||
|
process.on(signal, () => {
|
||||||
|
forwardSignal(signal);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
child.on('error', (error) => {
|
||||||
|
clean();
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
|
||||||
|
child.on('exit', (code, signal) => {
|
||||||
|
clean();
|
||||||
|
if (signal) {
|
||||||
|
process.kill(process.pid, signal);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
process.exit(code ?? 0);
|
||||||
|
});
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
const fs = require('node:fs');
|
||||||
|
const path = require('node:path');
|
||||||
|
|
||||||
|
const workspaceGlobalPath = path.resolve(__dirname, '../../../global.tsx');
|
||||||
|
const workspaceDependenciesPath = path.resolve(__dirname, '../../../dependencies.json');
|
||||||
|
const workspaceTsconfigPath = path.resolve(__dirname, '../../../tsconfig.json');
|
||||||
|
const targetGlobalPath = path.resolve(__dirname, '../src/global.tsx');
|
||||||
|
const targetPackageJsonPath = path.resolve(__dirname, '../package.json');
|
||||||
|
const targetTsconfigPath = path.resolve(__dirname, '../tsconfig.json');
|
||||||
|
const mode = process.argv[2] || 'append';
|
||||||
|
const blockStart = '// ENTERPRISE_PLUGIN_BLOCK_START';
|
||||||
|
const blockEnd = '// ENTERPRISE_PLUGIN_BLOCK_END';
|
||||||
|
|
||||||
|
const workspaceSource = fs.readFileSync(workspaceGlobalPath, 'utf8').trim();
|
||||||
|
const blockContent = `\n${blockStart}\n${workspaceSource}\n${blockEnd}\n`;
|
||||||
|
|
||||||
|
const stripBlock = (content) => {
|
||||||
|
const pattern = new RegExp(`\\n?${blockStart}[\\s\\S]*?${blockEnd}\\n?`, 'g');
|
||||||
|
return content.replace(pattern, '\n').replace(/\n{3,}/g, '\n\n').trimEnd() + '\n';
|
||||||
|
};
|
||||||
|
|
||||||
|
const currentContent = fs.readFileSync(targetGlobalPath, 'utf8');
|
||||||
|
const strippedContent = stripBlock(currentContent);
|
||||||
|
|
||||||
|
const readJson = (filePath) => JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
||||||
|
const writeJson = (filePath, data) => {
|
||||||
|
fs.writeFileSync(filePath, `${JSON.stringify(data, null, 2)}\n`);
|
||||||
|
};
|
||||||
|
|
||||||
|
const syncPackageJson = () => {
|
||||||
|
const sourceDependencies =
|
||||||
|
readJson(workspaceDependenciesPath).dependencies || {};
|
||||||
|
const targetPackageJson = readJson(targetPackageJsonPath);
|
||||||
|
const currentDependencies = {
|
||||||
|
...(targetPackageJson.dependencies || {})
|
||||||
|
};
|
||||||
|
|
||||||
|
if (mode === 'clean') {
|
||||||
|
Object.keys(sourceDependencies).forEach((dependencyName) => {
|
||||||
|
delete currentDependencies[dependencyName];
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Object.assign(currentDependencies, sourceDependencies);
|
||||||
|
}
|
||||||
|
|
||||||
|
targetPackageJson.dependencies = currentDependencies;
|
||||||
|
writeJson(targetPackageJsonPath, targetPackageJson);
|
||||||
|
console.log(
|
||||||
|
`${mode === 'clean' ? 'Cleaned' : 'Synced'} enterprise dependencies in ${targetPackageJsonPath}`,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const syncTsconfig = () => {
|
||||||
|
const sourcePaths =
|
||||||
|
readJson(workspaceTsconfigPath).compilerOptions?.paths || {};
|
||||||
|
const targetTsconfig = readJson(targetTsconfigPath);
|
||||||
|
const currentPaths = {
|
||||||
|
...(targetTsconfig.compilerOptions?.paths || {})
|
||||||
|
};
|
||||||
|
|
||||||
|
if (mode === 'clean') {
|
||||||
|
Object.keys(sourcePaths).forEach((pathKey) => {
|
||||||
|
delete currentPaths[pathKey];
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Object.assign(currentPaths, sourcePaths);
|
||||||
|
}
|
||||||
|
|
||||||
|
targetTsconfig.compilerOptions = targetTsconfig.compilerOptions || {};
|
||||||
|
targetTsconfig.compilerOptions.paths = currentPaths;
|
||||||
|
|
||||||
|
writeJson(targetTsconfigPath, targetTsconfig);
|
||||||
|
console.log(
|
||||||
|
`${mode === 'clean' ? 'Cleaned' : 'Synced'} enterprise tsconfig paths in ${targetTsconfigPath}`,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (mode === 'clean') {
|
||||||
|
if (strippedContent !== currentContent) {
|
||||||
|
fs.writeFileSync(targetGlobalPath, strippedContent);
|
||||||
|
console.log(`Cleaned enterprise plugin block from ${targetGlobalPath}`);
|
||||||
|
} else {
|
||||||
|
console.log(`Enterprise plugin block already absent: ${targetGlobalPath}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const updatedContent = `${strippedContent.trimEnd()}${blockContent}`;
|
||||||
|
if (updatedContent !== currentContent) {
|
||||||
|
fs.writeFileSync(targetGlobalPath, updatedContent);
|
||||||
|
console.log(`Appended enterprise plugin block to ${targetGlobalPath}`);
|
||||||
|
} else {
|
||||||
|
console.log(`Enterprise plugin block already up to date: ${targetGlobalPath}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
syncPackageJson();
|
||||||
|
syncTsconfig();
|
||||||
+26
-2
@@ -1,6 +1,9 @@
|
|||||||
import { GPUStackVersionAtom, UpdateCheckAtom } from '@/atoms/user';
|
import { GPUStackVersionAtom, UpdateCheckAtom } from '@/atoms/user';
|
||||||
import { setAtomStorage } from '@/atoms/utils';
|
import { setAtomStorage } from '@/atoms/utils';
|
||||||
import { DEFAULT_ENTER_PAGE, GPUSTACK_API_BASE_URL } from '@/config/settings';
|
import { DEFAULT_ENTER_PAGE, GPUSTACK_API_BASE_URL } from '@/config/settings';
|
||||||
|
import { getGPUStackPlugin } from '@/plugins';
|
||||||
|
import { GPUStackPluginManager } from '@/plugins/manager';
|
||||||
|
import { mergeEnterpriseRoutes } from '@/plugins/route-merger';
|
||||||
import { requestConfig } from '@/request-config';
|
import { requestConfig } from '@/request-config';
|
||||||
import {
|
import {
|
||||||
queryCurrentUserState,
|
queryCurrentUserState,
|
||||||
@@ -14,6 +17,7 @@ import {
|
|||||||
readState,
|
readState,
|
||||||
writeState
|
writeState
|
||||||
} from '@/utils/localstore/index';
|
} from '@/utils/localstore/index';
|
||||||
|
import '@gpustack/core-ui/style.css';
|
||||||
import { RequestConfig, history } from '@umijs/max';
|
import { RequestConfig, history } from '@umijs/max';
|
||||||
import { message } from 'antd';
|
import { message } from 'antd';
|
||||||
|
|
||||||
@@ -33,8 +37,18 @@ const checkDefaultPage = async (userInfo: any) => {
|
|||||||
export async function getInitialState(): Promise<{
|
export async function getInitialState(): Promise<{
|
||||||
fetchUserInfo: () => Promise<Global.UserInfo>;
|
fetchUserInfo: () => Promise<Global.UserInfo>;
|
||||||
currentUser?: Global.UserInfo;
|
currentUser?: Global.UserInfo;
|
||||||
|
pluginData?: Record<string, any>;
|
||||||
}> {
|
}> {
|
||||||
const { location } = history;
|
const { location } = history;
|
||||||
|
const enterprisePlugin = getGPUStackPlugin();
|
||||||
|
|
||||||
|
// initialize plugins and merge enterprise locales
|
||||||
|
let pluginData = {};
|
||||||
|
try {
|
||||||
|
pluginData = await GPUStackPluginManager.initialize();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to initialize plugins:', error);
|
||||||
|
}
|
||||||
|
|
||||||
const getUpdateCheck = async () => {
|
const getUpdateCheck = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -103,11 +117,13 @@ export async function getInitialState(): Promise<{
|
|||||||
checkDefaultPage(userInfo);
|
checkDefaultPage(userInfo);
|
||||||
return {
|
return {
|
||||||
fetchUserInfo,
|
fetchUserInfo,
|
||||||
currentUser: userInfo
|
currentUser: userInfo,
|
||||||
|
pluginData
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
fetchUserInfo
|
fetchUserInfo,
|
||||||
|
pluginData
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,3 +131,11 @@ export const request: RequestConfig = {
|
|||||||
baseURL: `/${GPUSTACK_API_BASE_URL}`,
|
baseURL: `/${GPUSTACK_API_BASE_URL}`,
|
||||||
...requestConfig
|
...requestConfig
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动态修改路由
|
||||||
|
* @param routes 路由配置
|
||||||
|
*/
|
||||||
|
export function patchClientRoutes({ routes }: any) {
|
||||||
|
mergeEnterpriseRoutes(routes);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import {
|
import {
|
||||||
InfiniteScroller,
|
InfiniteScroller,
|
||||||
ResizeContainer,
|
ResizeContainer,
|
||||||
TemplateCardSkeleton
|
TemplateCardSkeleton,
|
||||||
|
useScrollerContext
|
||||||
} from '@gpustack/core-ui';
|
} from '@gpustack/core-ui';
|
||||||
import { useScrollerContext } from '@gpustack/core-ui/lib/components/infinite-scroller/use-scroller-context';
|
|
||||||
import { Spin } from 'antd';
|
import { Spin } from 'antd';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
export const COLOR_PRIMARY = '#007BFF';
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { COLOR_PRIMARY } from './index';
|
import { COLOR_PRIMARY } from './constants';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
'root-entry-name': 'variable',
|
'root-entry-name': 'variable',
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
|
import { COLOR_PRIMARY } from './constants';
|
||||||
import dark from './dark';
|
import dark from './dark';
|
||||||
import light from './light';
|
import light from './light';
|
||||||
|
|
||||||
export const COLOR_PRIMARY = '#007BFF';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
light,
|
light,
|
||||||
dark,
|
dark,
|
||||||
colorPrimary: COLOR_PRIMARY
|
colorPrimary: COLOR_PRIMARY
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export { COLOR_PRIMARY };
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { COLOR_PRIMARY } from './index';
|
import { COLOR_PRIMARY } from './constants';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
'root-entry-name': 'variable',
|
'root-entry-name': 'variable',
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { userSettingsHelperAtom } from '@/atoms/settings';
|
||||||
|
import { getAtomStorage, setAtomStorage } from '@/atoms/utils';
|
||||||
|
|
||||||
|
export default function useUserSettingsStorage() {
|
||||||
|
const setStorageUserSettings = (value: Record<string, any>) => {
|
||||||
|
setAtomStorage(userSettingsHelperAtom, value || {});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getStorageUserSettings = () => {
|
||||||
|
return getAtomStorage(userSettingsHelperAtom);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
setStorageUserSettings,
|
||||||
|
getStorageUserSettings
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { userSettingsHelperAtom } from '@/atoms/settings';
|
|
||||||
import themeConfig from '@/config/theme';
|
|
||||||
import { useAtom } from 'jotai';
|
import { useAtom } from 'jotai';
|
||||||
import { useEffect, useMemo } from 'react';
|
import { useEffect, useMemo } from 'react';
|
||||||
|
import { userSettingsHelperAtom } from '../atoms/settings';
|
||||||
|
import themeConfig from '../config/theme';
|
||||||
|
|
||||||
type Theme = 'light' | 'realDark' | 'auto';
|
type Theme = 'light' | 'realDark' | 'auto';
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import VersionInfo, { modalConfig } from '@/components/version-info';
|
|||||||
import externalLinks from '@/constants/external-links';
|
import externalLinks from '@/constants/external-links';
|
||||||
import useBodyScroll from '@/hooks/use-body-scroll';
|
import useBodyScroll from '@/hooks/use-body-scroll';
|
||||||
import { logout } from '@/pages/login/apis';
|
import { logout } from '@/pages/login/apis';
|
||||||
|
import { getGPUStackPlugin } from '@/plugins';
|
||||||
import { useModel } from '@@/plugin-model';
|
import { useModel } from '@@/plugin-model';
|
||||||
import {
|
import {
|
||||||
DiscordOutlined,
|
DiscordOutlined,
|
||||||
@@ -105,6 +106,7 @@ const CustomItem = styled.div`
|
|||||||
|
|
||||||
export const ExtraContent = (props: { isDarkTheme?: boolean }) => {
|
export const ExtraContent = (props: { isDarkTheme?: boolean }) => {
|
||||||
const { isDarkTheme } = props;
|
const { isDarkTheme } = props;
|
||||||
|
const pluginManager = getGPUStackPlugin();
|
||||||
const { saveScrollHeight, restoreScrollHeight } = useBodyScroll();
|
const { saveScrollHeight, restoreScrollHeight } = useBodyScroll();
|
||||||
const [modal, contextHolder] = Modal.useModal();
|
const [modal, contextHolder] = Modal.useModal();
|
||||||
const [version] = useAtom(GPUStackVersionAtom);
|
const [version] = useAtom(GPUStackVersionAtom);
|
||||||
@@ -117,6 +119,7 @@ export const ExtraContent = (props: { isDarkTheme?: boolean }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const { initialState } = initialInfo;
|
const { initialState } = initialInfo;
|
||||||
|
console.log('plugin+++++++++', pluginManager);
|
||||||
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
@@ -291,6 +294,18 @@ export const ExtraContent = (props: { isDarkTheme?: boolean }) => {
|
|||||||
</NewLabel>
|
</NewLabel>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
size="small"
|
||||||
|
onClick={() => {
|
||||||
|
history.push('/settings');
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
color: 'var(--ant-color-text-tertiary)'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<IconFont type="icon-settings-02" style={{ fontSize: 18 }} />
|
||||||
|
</Button>
|
||||||
<DropdownActions menu={{ ...helpMenu }} popupRender={helpPopupRender}>
|
<DropdownActions menu={{ ...helpMenu }} popupRender={helpPopupRender}>
|
||||||
<IconWrapper>
|
<IconWrapper>
|
||||||
<IconFont
|
<IconFont
|
||||||
|
|||||||
+17
-3
@@ -3,8 +3,10 @@ import { userAtom } from '@/atoms/user';
|
|||||||
import DarkMask from '@/components/dark-mask';
|
import DarkMask from '@/components/dark-mask';
|
||||||
import routeCachekey from '@/config/route-cachekey';
|
import routeCachekey from '@/config/route-cachekey';
|
||||||
import { DEFAULT_ENTER_PAGE, GPUSTACK_API_BASE_URL } from '@/config/settings';
|
import { DEFAULT_ENTER_PAGE, GPUSTACK_API_BASE_URL } from '@/config/settings';
|
||||||
|
import { COLOR_PRIMARY } from '@/config/theme';
|
||||||
import useOverlayScroller from '@/hooks/use-overlay-scroller';
|
import useOverlayScroller from '@/hooks/use-overlay-scroller';
|
||||||
import useUserSettings from '@/hooks/use-user-settings';
|
import useUserSettings from '@/hooks/use-user-settings';
|
||||||
|
import useUserSettingsStorage from '@/hooks/use-user-settings-storage';
|
||||||
import useAddResource from '@/pages/dashboard/hooks/use-add-resource';
|
import useAddResource from '@/pages/dashboard/hooks/use-add-resource';
|
||||||
import { logout } from '@/pages/login/apis';
|
import { logout } from '@/pages/login/apis';
|
||||||
import {
|
import {
|
||||||
@@ -128,6 +130,7 @@ export default (props: any) => {
|
|||||||
});
|
});
|
||||||
const [, contextHolder] = Modal.useModal();
|
const [, contextHolder] = Modal.useModal();
|
||||||
const { themeData, setUserSettings, userSettings } = useUserSettings();
|
const { themeData, setUserSettings, userSettings } = useUserSettings();
|
||||||
|
const userSettingsStorage = useUserSettingsStorage();
|
||||||
const [userInfo] = useAtom(userAtom);
|
const [userInfo] = useAtom(userAtom);
|
||||||
const [routeCache] = useAtom(routeCacheAtom);
|
const [routeCache] = useAtom(routeCacheAtom);
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
@@ -205,7 +208,7 @@ export default (props: any) => {
|
|||||||
|
|
||||||
const role = initialState?.currentUser?.is_admin ? 'admin' : 'user';
|
const role = initialState?.currentUser?.is_admin ? 'admin' : 'user';
|
||||||
const [route] = useAccessMarkedRoutes(mapRoutes(newRoutes, role));
|
const [route] = useAccessMarkedRoutes(mapRoutes(newRoutes, role));
|
||||||
|
console.log('route++++++++', route, clientRoutes);
|
||||||
patchRoutes({
|
patchRoutes({
|
||||||
routes: route.children,
|
routes: route.children,
|
||||||
initialState: initialInfo.initialState
|
initialState: initialInfo.initialState
|
||||||
@@ -363,7 +366,13 @@ export default (props: any) => {
|
|||||||
apiBaseUrl: GPUSTACK_API_BASE_URL,
|
apiBaseUrl: GPUSTACK_API_BASE_URL,
|
||||||
theme: userSettings.theme,
|
theme: userSettings.theme,
|
||||||
iconUrl: '//at.alicdn.com/t/c/font_4613488_8fi68fmt1th.js',
|
iconUrl: '//at.alicdn.com/t/c/font_4613488_8fi68fmt1th.js',
|
||||||
isDarkTheme: userSettings.isDarkTheme
|
isDarkTheme: userSettings.isDarkTheme,
|
||||||
|
defaultColorPrimary: COLOR_PRIMARY
|
||||||
|
}}
|
||||||
|
hooks={{
|
||||||
|
useUserSettings: useUserSettings,
|
||||||
|
useUserSettingsStorage: () => userSettingsStorage,
|
||||||
|
useIntl: useIntl
|
||||||
}}
|
}}
|
||||||
i18n={intl}
|
i18n={intl}
|
||||||
locale={{
|
locale={{
|
||||||
@@ -371,7 +380,12 @@ export default (props: any) => {
|
|||||||
setLocale: setLocale
|
setLocale: setLocale
|
||||||
}}
|
}}
|
||||||
services={{
|
services={{
|
||||||
request: request
|
request: request,
|
||||||
|
router: {
|
||||||
|
push: (path: string) => navigate(path),
|
||||||
|
replace: (path: string) => navigate(path, { replace: true }),
|
||||||
|
goBack: () => navigate(-1)
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
localStore={{
|
localStore={{
|
||||||
readColumnSettings,
|
readColumnSettings,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// columns.ts
|
// columns.ts
|
||||||
import { tableSorter } from '@/config/settings';
|
import { tableSorter } from '@/config/settings';
|
||||||
import { AutoTooltip, DropdownButtons } from '@gpustack/core-ui';
|
import { AutoTooltip, DropdownButtons, icons } from '@gpustack/core-ui';
|
||||||
import icons from '@gpustack/core-ui/lib/components/icon-font/icons';
|
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Tag } from 'antd';
|
import { Tag } from 'antd';
|
||||||
import { ColumnsType } from 'antd/lib/table';
|
import { ColumnsType } from 'antd/lib/table';
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import {
|
import {
|
||||||
InfiniteScroller,
|
InfiniteScroller,
|
||||||
ResizeContainer,
|
ResizeContainer,
|
||||||
TemplateCardSkeleton
|
TemplateCardSkeleton,
|
||||||
|
useScrollerContext
|
||||||
} from '@gpustack/core-ui';
|
} from '@gpustack/core-ui';
|
||||||
import { useScrollerContext } from '@gpustack/core-ui/lib/components/infinite-scroller/use-scroller-context';
|
|
||||||
import { Spin } from 'antd';
|
import { Spin } from 'antd';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import backendListCss from '../styles/backend-list.less';
|
import backendListCss from '../styles/backend-list.less';
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
GPUDriverMap,
|
GPUDriverMap,
|
||||||
ManufacturerMap
|
ManufacturerMap
|
||||||
} from '@/pages/resources/config/gpu-driver';
|
} from '@/pages/resources/config/gpu-driver';
|
||||||
import icons from '@gpustack/core-ui/lib/components/icon-font/icons';
|
import { icons } from '@gpustack/core-ui';
|
||||||
import jsYaml from 'js-yaml';
|
import jsYaml from 'js-yaml';
|
||||||
import { trim } from 'lodash';
|
import { trim } from 'lodash';
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
import { DownloadOutlined } from '@ant-design/icons';
|
import { DownloadOutlined } from '@ant-design/icons';
|
||||||
import { DropdownButtons, IconFont, useDownloadLogs } from '@gpustack/core-ui';
|
import {
|
||||||
import icons from '@gpustack/core-ui/lib/components/icon-font/icons';
|
DropdownButtons,
|
||||||
|
IconFont,
|
||||||
|
icons,
|
||||||
|
useDownloadLogs
|
||||||
|
} from '@gpustack/core-ui';
|
||||||
import { BENCHMARKS_API } from '../apis';
|
import { BENCHMARKS_API } from '../apis';
|
||||||
import { BenchmarkStatusValueMap } from '../config';
|
import { BenchmarkStatusValueMap } from '../config';
|
||||||
import { BenchmarkListItem as ListItem } from '../config/types';
|
import { BenchmarkListItem as ListItem } from '../config/types';
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
import { PageAction } from '@/config';
|
import { PageAction } from '@/config';
|
||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
import { CollapsePanel, IconFont, ScrollSpyTabs } from '@gpustack/core-ui';
|
import {
|
||||||
import { useWrapperContext } from '@gpustack/core-ui/lib/components/column-wrapper/use-wrapper-context';
|
CollapsePanel,
|
||||||
|
IconFont,
|
||||||
|
ScrollSpyTabs,
|
||||||
|
useWrapperContext
|
||||||
|
} from '@gpustack/core-ui';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Form } from 'antd';
|
import { Form } from 'antd';
|
||||||
import {
|
import {
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ import {
|
|||||||
FilterBar,
|
FilterBar,
|
||||||
IconFont,
|
IconFont,
|
||||||
Table as SealTable,
|
Table as SealTable,
|
||||||
|
TableOrder,
|
||||||
TableProvider
|
TableProvider
|
||||||
} from '@gpustack/core-ui';
|
} from '@gpustack/core-ui';
|
||||||
import { TableOrder } from '@gpustack/core-ui/lib/components/table/types';
|
|
||||||
import { useIntl, useNavigate } from '@umijs/max';
|
import { useIntl, useNavigate } from '@umijs/max';
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import { message } from 'antd';
|
import { message } from 'antd';
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import { DropdownActions } from '@gpustack/core-ui';
|
import { DropdownActions, type FieldSchema, ListMap } from '@gpustack/core-ui';
|
||||||
import ListMap from '@gpustack/core-ui/lib/components/dynamic-form/components/list-map';
|
|
||||||
import { FieldSchema } from '@gpustack/core-ui/lib/components/dynamic-form/config/types';
|
|
||||||
|
|
||||||
import { PlusOutlined } from '@ant-design/icons';
|
import { PlusOutlined } from '@ant-design/icons';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ import {
|
|||||||
IconFont,
|
IconFont,
|
||||||
LabelSelector,
|
LabelSelector,
|
||||||
Select as SealSelect,
|
Select as SealSelect,
|
||||||
useAppUtils
|
useAppUtils,
|
||||||
|
type CollapseContainerProps
|
||||||
} from '@gpustack/core-ui';
|
} from '@gpustack/core-ui';
|
||||||
import { type CollapseContainerProps } from '@gpustack/core-ui/lib/components/collapse-container';
|
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import { Button, Form } from 'antd';
|
import { Button, Form } from 'antd';
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import ListMap from '@gpustack/core-ui/lib/components/dynamic-form/components/list-map';
|
import { ListMap, type statusType, useValidateFields } from '@gpustack/core-ui';
|
||||||
import { statusType } from '@gpustack/core-ui/lib/components/dynamic-form/config/types';
|
|
||||||
import useValidateFields from '@gpustack/core-ui/lib/components/dynamic-form/hooks/use-validate-fields';
|
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Form } from 'antd';
|
import { Form } from 'antd';
|
||||||
import React, { forwardRef, useState } from 'react';
|
import React, { forwardRef, useState } from 'react';
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { FieldSchema } from '@gpustack/core-ui/lib/components/dynamic-form/config/types';
|
import { type FieldSchema } from '@gpustack/core-ui';
|
||||||
|
|
||||||
export const fields = {
|
export const fields = {
|
||||||
volumes: {
|
volumes: {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { StatusMaps } from '@/config';
|
|||||||
import { GPUSTACK_API_BASE_URL } from '@/config/settings';
|
import { GPUSTACK_API_BASE_URL } from '@/config/settings';
|
||||||
import { StatusType } from '@/config/types';
|
import { StatusType } from '@/config/types';
|
||||||
import { GPUsConfigs } from '@/pages/resources/config/gpu-driver';
|
import { GPUsConfigs } from '@/pages/resources/config/gpu-driver';
|
||||||
import icons from '@gpustack/core-ui/lib/components/icon-font/icons';
|
import { icons } from '@gpustack/core-ui';
|
||||||
|
|
||||||
export const ClusterStatusValueMap = {
|
export const ClusterStatusValueMap = {
|
||||||
Provisioning: 'provisioning',
|
Provisioning: 'provisioning',
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import icons from '@gpustack/core-ui/lib/components/icon-font/icons';
|
import { icons } from '@gpustack/core-ui';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ProviderValueMap } from '.';
|
import { ProviderValueMap } from '.';
|
||||||
|
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ import {
|
|||||||
AutoTooltip,
|
AutoTooltip,
|
||||||
DropdownButtons,
|
DropdownButtons,
|
||||||
GrafanaIcon,
|
GrafanaIcon,
|
||||||
StatusTag
|
StatusTag,
|
||||||
|
icons,
|
||||||
|
type TableColumnProps as SealColumnProps
|
||||||
} from '@gpustack/core-ui';
|
} from '@gpustack/core-ui';
|
||||||
import icons from '@gpustack/core-ui/lib/components/icon-font/icons';
|
|
||||||
import { ColumnProps as SealColumnProps } from '@gpustack/core-ui/lib/components/table/types';
|
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Tooltip } from 'antd';
|
import { Tooltip } from 'antd';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import { DeleteOutlined, EditOutlined } from '@ant-design/icons';
|
import { DeleteOutlined, EditOutlined } from '@ant-design/icons';
|
||||||
import { AutoTooltip, DropdownButtons } from '@gpustack/core-ui';
|
import {
|
||||||
import { ColumnProps } from '@gpustack/core-ui/lib/components/table/types';
|
AutoTooltip,
|
||||||
|
DropdownButtons,
|
||||||
|
type TableColumnProps
|
||||||
|
} from '@gpustack/core-ui';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
@@ -27,7 +30,7 @@ const actionItems = [
|
|||||||
const usePoolsColumns = (
|
const usePoolsColumns = (
|
||||||
handleSelect: (val: string, record: ListItem) => void,
|
handleSelect: (val: string, record: ListItem) => void,
|
||||||
sortOrder?: string[]
|
sortOrder?: string[]
|
||||||
): ColumnProps[] => {
|
): TableColumnProps[] => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import {
|
import {
|
||||||
InfiniteScroller,
|
InfiniteScroller,
|
||||||
ResizeContainer,
|
ResizeContainer,
|
||||||
TemplateCardSkeleton
|
TemplateCardSkeleton,
|
||||||
|
useScrollerContext
|
||||||
} from '@gpustack/core-ui';
|
} from '@gpustack/core-ui';
|
||||||
import { useScrollerContext } from '@gpustack/core-ui/lib/components/infinite-scroller/use-scroller-context';
|
|
||||||
import { Spin } from 'antd';
|
import { Spin } from 'antd';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ import { useBenchmarkTargetInstance } from '@/pages/llmodels/hooks/use-run-bench
|
|||||||
import { DeleteOutlined, DownloadOutlined } from '@ant-design/icons';
|
import { DeleteOutlined, DownloadOutlined } from '@ant-design/icons';
|
||||||
import {
|
import {
|
||||||
DropdownButtons,
|
DropdownButtons,
|
||||||
|
type HandlerOptions,
|
||||||
IconFont,
|
IconFont,
|
||||||
useDownloadStream
|
useDownloadStream
|
||||||
} from '@gpustack/core-ui';
|
} from '@gpustack/core-ui';
|
||||||
import { HandlerOptions } from '@gpustack/core-ui/lib/hooks/use-chunk-fetch';
|
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Progress, notification } from 'antd';
|
import { Progress, notification } from 'antd';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { ListItem as WorkerListItem } from '@/pages/resources/config/types';
|
import { ListItem as WorkerListItem } from '@/pages/resources/config/types';
|
||||||
import { SimpleTable, StatusTag } from '@gpustack/core-ui';
|
import { SimpleTable, StatusTag, type ColumnProps } from '@gpustack/core-ui';
|
||||||
import { type ColumnProps } from '@gpustack/core-ui/lib/components/simple-table';
|
|
||||||
import { Progress, Tooltip } from 'antd';
|
import { Progress, Tooltip } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { InstanceStatusMap, status } from '../../config';
|
import { InstanceStatusMap, status } from '../../config';
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ import {
|
|||||||
DropdownActions,
|
DropdownActions,
|
||||||
DropdownButtons,
|
DropdownButtons,
|
||||||
PageTools,
|
PageTools,
|
||||||
Table as SealTable
|
Table as SealTable,
|
||||||
|
TableOrder
|
||||||
} from '@gpustack/core-ui';
|
} from '@gpustack/core-ui';
|
||||||
import { TableOrder } from '@gpustack/core-ui/lib/components/table/types';
|
|
||||||
import { useIntl, useNavigate, useSearchParams } from '@umijs/max';
|
import { useIntl, useNavigate, useSearchParams } from '@umijs/max';
|
||||||
import { useMemoizedFn, useToggle } from 'ahooks';
|
import { useMemoizedFn, useToggle } from 'ahooks';
|
||||||
import { Button, Space, message } from 'antd';
|
import { Button, Space, message } from 'antd';
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import HotKeys from '@/config/hotkeys';
|
import HotKeys from '@/config/hotkeys';
|
||||||
import icons from '@gpustack/core-ui/lib/components/icon-font/icons';
|
import { icons } from '@gpustack/core-ui';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { modelCategoriesMap, modelSourceMap } from './index';
|
import { modelCategoriesMap, modelSourceMap } from './index';
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ import useSetChunkRequest from '@/hooks/use-chunk-request';
|
|||||||
import { usePaginationStatus } from '@/hooks/use-pagination-status';
|
import { usePaginationStatus } from '@/hooks/use-pagination-status';
|
||||||
import { useTableMultiSort } from '@/hooks/use-table-sort';
|
import { useTableMultiSort } from '@/hooks/use-table-sort';
|
||||||
import useUpdateChunkedList from '@/hooks/use-update-chunk-list';
|
import useUpdateChunkedList from '@/hooks/use-update-chunk-list';
|
||||||
import { TableProvider } from '@gpustack/core-ui';
|
import { TableOrder, TableProvider } from '@gpustack/core-ui';
|
||||||
import { TableOrder } from '@gpustack/core-ui/lib/components/table/types';
|
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import qs from 'query-string';
|
import qs from 'query-string';
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
import { PageAction } from '@/config';
|
import { PageAction } from '@/config';
|
||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
import { CollapsePanel, IconFont, ScrollSpyTabs } from '@gpustack/core-ui';
|
import {
|
||||||
import { useWrapperContext } from '@gpustack/core-ui/lib/components/column-wrapper/use-wrapper-context';
|
CollapsePanel,
|
||||||
|
IconFont,
|
||||||
|
ScrollSpyTabs,
|
||||||
|
useWrapperContext
|
||||||
|
} from '@gpustack/core-ui';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Form } from 'antd';
|
import { Form } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|||||||
@@ -3,9 +3,13 @@ import { systemConfigAtom } from '@/atoms/system';
|
|||||||
import { OPENAI_COMPATIBLE, tableSorter } from '@/config/settings';
|
import { OPENAI_COMPATIBLE, tableSorter } from '@/config/settings';
|
||||||
import { TargetStatusValueMap } from '@/pages/model-routes/config';
|
import { TargetStatusValueMap } from '@/pages/model-routes/config';
|
||||||
import { QuestionCircleOutlined } from '@ant-design/icons';
|
import { QuestionCircleOutlined } from '@ant-design/icons';
|
||||||
import { AutoTooltip, DropdownButtons, GrafanaIcon } from '@gpustack/core-ui';
|
import {
|
||||||
import icons from '@gpustack/core-ui/lib/components/icon-font/icons';
|
AutoTooltip,
|
||||||
import { ColumnProps } from '@gpustack/core-ui/lib/components/table/types';
|
DropdownButtons,
|
||||||
|
GrafanaIcon,
|
||||||
|
icons,
|
||||||
|
type TableColumnProps
|
||||||
|
} from '@gpustack/core-ui';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import { Tooltip } from 'antd';
|
import { Tooltip } from 'antd';
|
||||||
@@ -98,7 +102,7 @@ const useModelsColumns = ({
|
|||||||
clusterList,
|
clusterList,
|
||||||
sortOrder,
|
sortOrder,
|
||||||
targetList
|
targetList
|
||||||
}: ModelsColumnsHookProps & { targetList: any[] }): ColumnProps[] => {
|
}: ModelsColumnsHookProps & { targetList: any[] }): TableColumnProps[] => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const systemConfig = useAtomValue(systemConfigAtom);
|
const systemConfig = useAtomValue(systemConfigAtom);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import useBodyScroll from '@/hooks/use-body-scroll';
|
import useBodyScroll from '@/hooks/use-body-scroll';
|
||||||
import { PageSize } from '@gpustack/core-ui/lib/components/logs-viewer/config';
|
import { PageSize } from '@gpustack/core-ui';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { MODEL_INSTANCE_API } from '../apis';
|
import { MODEL_INSTANCE_API } from '../apis';
|
||||||
import { InstanceRealtimeLogStatus } from '../config';
|
import { InstanceRealtimeLogStatus } from '../config';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { StatusMaps } from '@/config';
|
import { StatusMaps } from '@/config';
|
||||||
import { StatusType } from '@/config/types';
|
import { StatusType } from '@/config/types';
|
||||||
import icons from '@gpustack/core-ui/lib/components/icon-font/icons';
|
import { icons } from '@gpustack/core-ui';
|
||||||
import { ProviderEnum } from './providers';
|
import { ProviderEnum } from './providers';
|
||||||
export { maasProviderLabelMap, maasProviderOptions } from './providers';
|
export { maasProviderLabelMap, maasProviderOptions } from './providers';
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
import { PageAction } from '@/config';
|
import { PageAction } from '@/config';
|
||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
import { json2Yaml, yaml2Json } from '@/pages/backends/config';
|
import { json2Yaml, yaml2Json } from '@/pages/backends/config';
|
||||||
import { CollapsePanel, IconFont, ScrollSpyTabs } from '@gpustack/core-ui';
|
import {
|
||||||
import { useWrapperContext } from '@gpustack/core-ui/lib/components/column-wrapper/use-wrapper-context';
|
CollapsePanel,
|
||||||
import useFinishFailed from '@gpustack/core-ui/lib/components/scroll-spy-tabs/use-finish-failed';
|
IconFont,
|
||||||
import useScrollActiveChange from '@gpustack/core-ui/lib/components/scroll-spy-tabs/use-scroll-active-change';
|
ScrollSpyTabs,
|
||||||
|
useFinishFailed,
|
||||||
|
useScrollActiveChange,
|
||||||
|
useWrapperContext
|
||||||
|
} from '@gpustack/core-ui';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Form } from 'antd';
|
import { Form } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { StatusMaps } from '@/config';
|
import { StatusMaps } from '@/config';
|
||||||
import { StatusType } from '@/config/types';
|
import { StatusType } from '@/config/types';
|
||||||
import icons from '@gpustack/core-ui/lib/components/icon-font/icons';
|
import { icons } from '@gpustack/core-ui';
|
||||||
|
|
||||||
export const TargetStatusValueMap: Record<string, string> = {
|
export const TargetStatusValueMap: Record<string, string> = {
|
||||||
Active: 'active',
|
Active: 'active',
|
||||||
|
|||||||
@@ -1,10 +1,14 @@
|
|||||||
import { PageAction } from '@/config';
|
import { PageAction } from '@/config';
|
||||||
import { PageActionType } from '@/config/types';
|
import { PageActionType } from '@/config/types';
|
||||||
import { modelCategoriesMap } from '@/pages/llmodels/config';
|
import { modelCategoriesMap } from '@/pages/llmodels/config';
|
||||||
import { CollapsePanel, IconFont, ScrollSpyTabs } from '@gpustack/core-ui';
|
import {
|
||||||
import { useWrapperContext } from '@gpustack/core-ui/lib/components/column-wrapper/use-wrapper-context';
|
CollapsePanel,
|
||||||
import useFinishFailed from '@gpustack/core-ui/lib/components/scroll-spy-tabs/use-finish-failed';
|
IconFont,
|
||||||
import useScrollActiveChange from '@gpustack/core-ui/lib/components/scroll-spy-tabs/use-scroll-active-change';
|
ScrollSpyTabs,
|
||||||
|
useFinishFailed,
|
||||||
|
useScrollActiveChange,
|
||||||
|
useWrapperContext
|
||||||
|
} from '@gpustack/core-ui';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Form } from 'antd';
|
import { Form } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
// columns.ts
|
// columns.ts
|
||||||
import { tableSorter } from '@/config/settings';
|
import { tableSorter } from '@/config/settings';
|
||||||
import ModelTag from '@/pages/_components/model-tag';
|
import ModelTag from '@/pages/_components/model-tag';
|
||||||
import { AutoTooltip, DropdownButtons } from '@gpustack/core-ui';
|
import {
|
||||||
import { type ColumnProps } from '@gpustack/core-ui/lib/components/table/types';
|
AutoTooltip,
|
||||||
|
DropdownButtons,
|
||||||
|
type TableColumnProps
|
||||||
|
} from '@gpustack/core-ui';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
@@ -11,7 +14,7 @@ import { RouteItem } from '../config/types';
|
|||||||
const useAccessColumns = (
|
const useAccessColumns = (
|
||||||
handleSelect: (val: string, record: RouteItem) => void,
|
handleSelect: (val: string, record: RouteItem) => void,
|
||||||
onCellClick?: (record: RouteItem, dataIndex: string) => void
|
onCellClick?: (record: RouteItem, dataIndex: string) => void
|
||||||
): ColumnProps[] => {
|
): TableColumnProps[] => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const filterActions = (record: RouteItem) => {
|
const filterActions = (record: RouteItem) => {
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ import {
|
|||||||
FilterBar,
|
FilterBar,
|
||||||
IconFont,
|
IconFont,
|
||||||
Table as SealTable,
|
Table as SealTable,
|
||||||
|
TableOrder,
|
||||||
TableProvider
|
TableProvider
|
||||||
} from '@gpustack/core-ui';
|
} from '@gpustack/core-ui';
|
||||||
import { TableOrder } from '@gpustack/core-ui/lib/components/table/types';
|
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import { message } from 'antd';
|
import { message } from 'antd';
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import {
|
|||||||
AlertInfo,
|
AlertInfo,
|
||||||
ImageEditor as CanvasImageEditor,
|
ImageEditor as CanvasImageEditor,
|
||||||
IconFont,
|
IconFont,
|
||||||
|
processImage,
|
||||||
SingleImage
|
SingleImage
|
||||||
} from '@gpustack/core-ui';
|
} from '@gpustack/core-ui';
|
||||||
import { processImage } from '@gpustack/core-ui/lib/components/image-editor/extract-image-colors';
|
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Divider } from 'antd';
|
import { Divider } from 'antd';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { getGPUStackPlugin } from '@/plugins';
|
||||||
|
import { Result } from 'antd';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const SettingsPage: React.FC = () => {
|
||||||
|
const enterprisePlugin = getGPUStackPlugin();
|
||||||
|
const BrandingUI = enterprisePlugin?.components?.BrandingUI;
|
||||||
|
|
||||||
|
if (!BrandingUI) {
|
||||||
|
return (
|
||||||
|
<Result
|
||||||
|
status="404"
|
||||||
|
title="404"
|
||||||
|
subTitle="Enterprise settings page is unavailable."
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <BrandingUI />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SettingsPage;
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
// columns.ts
|
// columns.ts
|
||||||
import { tableSorter } from '@/config/settings';
|
import { tableSorter } from '@/config/settings';
|
||||||
import { AutoTooltip, DropdownButtons, IconFont } from '@gpustack/core-ui';
|
import {
|
||||||
import icons from '@gpustack/core-ui/lib/components/icon-font/icons';
|
AutoTooltip,
|
||||||
|
DropdownButtons,
|
||||||
|
IconFont,
|
||||||
|
icons
|
||||||
|
} from '@gpustack/core-ui';
|
||||||
import { useIntl, useModel } from '@umijs/max';
|
import { useIntl, useModel } from '@umijs/max';
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import { Tag } from 'antd';
|
import { Tag } from 'antd';
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { GPUStackPluginManager } from './manager';
|
||||||
|
import { AppPlugin } from './types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook to access the enterprise plugin instance
|
||||||
|
*/
|
||||||
|
export const getGPUStackPlugin = (): AppPlugin | undefined => {
|
||||||
|
return GPUStackPluginManager.get('enterprise');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook to access a plugin by its name
|
||||||
|
*/
|
||||||
|
export const getPlugin = (name: string): AppPlugin | undefined => {
|
||||||
|
return GPUStackPluginManager.get(name);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook to check if a plugin is registered
|
||||||
|
*/
|
||||||
|
export const hasPlugin = (name: string): boolean => {
|
||||||
|
return GPUStackPluginManager.has(name);
|
||||||
|
};
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { addLocale } from '@umijs/max';
|
||||||
|
|
||||||
|
const mergedLocales = new Set<string>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merge enterprise plugin locales into the main application
|
||||||
|
*/
|
||||||
|
export function mergeEnterpriseLocales(locales: Record<string, any> = {}) {
|
||||||
|
if (!locales) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Merging enterprise plugin locales:', Object.keys(locales));
|
||||||
|
|
||||||
|
// Iterate over all locale configurations of the enterprise plugin
|
||||||
|
Object.entries(locales).forEach(([locale, messages]) => {
|
||||||
|
try {
|
||||||
|
if (mergedLocales.has(locale)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge the enterprise locale into the main application
|
||||||
|
addLocale(locale, messages, {
|
||||||
|
momentLocale: '',
|
||||||
|
// @ts-ignore
|
||||||
|
antd: locale
|
||||||
|
});
|
||||||
|
mergedLocales.add(locale);
|
||||||
|
console.log(`✓ Merged enterprise locale: ${locale}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Failed to merge enterprise locale ${locale}:`, error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
import { AppPlugin, IPluginManager } from './types';
|
||||||
|
|
||||||
|
class PluginManager implements IPluginManager {
|
||||||
|
private plugins = new Map<string, AppPlugin>();
|
||||||
|
private initialized = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* register a plugin
|
||||||
|
*/
|
||||||
|
register(name: string, plugin: AppPlugin) {
|
||||||
|
if (this.plugins.has(name)) {
|
||||||
|
console.warn(`Plugin "${name}" is already registered. Overwriting...`);
|
||||||
|
}
|
||||||
|
this.plugins.set(name, plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get a plugin
|
||||||
|
*/
|
||||||
|
get(name: string): AppPlugin | undefined {
|
||||||
|
return this.plugins.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check if a plugin exists
|
||||||
|
*/
|
||||||
|
has(name: string): boolean {
|
||||||
|
return this.plugins.has(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get all plugins
|
||||||
|
*/
|
||||||
|
getAll(): Map<string, AppPlugin> {
|
||||||
|
return this.plugins;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* initialize all plugins
|
||||||
|
*/
|
||||||
|
async initialize(): Promise<Record<string, any>> {
|
||||||
|
if (this.initialized) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const initData: Record<string, any> = {};
|
||||||
|
|
||||||
|
for (const [name, plugin] of this.plugins.entries()) {
|
||||||
|
if (plugin.onAppInit) {
|
||||||
|
try {
|
||||||
|
const data = await plugin.onAppInit();
|
||||||
|
if (data) {
|
||||||
|
initData[name] = data;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Failed to initialize plugin "${name}":`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.initialized = true;
|
||||||
|
return initData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通知所有插件应用已就绪
|
||||||
|
*/
|
||||||
|
async notifyReady(): Promise<void> {
|
||||||
|
for (const [name, plugin] of this.plugins.entries()) {
|
||||||
|
if (plugin.onAppReady) {
|
||||||
|
try {
|
||||||
|
await plugin.onAppReady();
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Plugin "${name}" onAppReady failed:`, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const GPUStackPluginManager = new PluginManager();
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
// If the enterprise plugin is not installed, imports will be redirected to this empty module to prevent errors.
|
||||||
|
export default undefined;
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import { getGPUStackPlugin } from '@/plugins';
|
||||||
|
import type { RouteConfig } from '@/plugins/types';
|
||||||
|
|
||||||
|
type ClientRoute = RouteConfig & {
|
||||||
|
id?: string;
|
||||||
|
children?: ClientRoute[];
|
||||||
|
routes?: ClientRoute[];
|
||||||
|
};
|
||||||
|
|
||||||
|
function getLayoutChildren(routes: ClientRoute[]): ClientRoute[] | null {
|
||||||
|
const rootRoute = routes.find((route) => route.path === '/');
|
||||||
|
if (!rootRoute) return null;
|
||||||
|
|
||||||
|
const rootChildren = rootRoute.routes || rootRoute.children;
|
||||||
|
if (!Array.isArray(rootChildren)) return null;
|
||||||
|
|
||||||
|
const globalLayout = rootChildren.find((route) =>
|
||||||
|
route.id?.includes('global-layout')
|
||||||
|
);
|
||||||
|
if (!globalLayout) return null;
|
||||||
|
|
||||||
|
const layoutChildren = globalLayout.children || globalLayout.routes;
|
||||||
|
return Array.isArray(layoutChildren) ? layoutChildren : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mergeRoute(targetRoutes: ClientRoute[], pluginRoute: ClientRoute) {
|
||||||
|
const existsIndex = targetRoutes.findIndex(
|
||||||
|
(route) =>
|
||||||
|
(pluginRoute.path && route.path === pluginRoute.path) ||
|
||||||
|
(pluginRoute.key && route.key === pluginRoute.key)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existsIndex === -1) {
|
||||||
|
targetRoutes.push(pluginRoute);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentRoute = targetRoutes[existsIndex];
|
||||||
|
targetRoutes[existsIndex] = {
|
||||||
|
...currentRoute,
|
||||||
|
...pluginRoute,
|
||||||
|
routes: pluginRoute.routes || currentRoute.routes,
|
||||||
|
children: pluginRoute.children || currentRoute.children
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mergeEnterpriseRoutes(routes: ClientRoute[]) {
|
||||||
|
const enterprisePlugin = getGPUStackPlugin();
|
||||||
|
if (!enterprisePlugin?.routes?.length) return;
|
||||||
|
|
||||||
|
const layoutChildren = getLayoutChildren(routes);
|
||||||
|
if (!layoutChildren) return;
|
||||||
|
|
||||||
|
enterprisePlugin.routes.forEach((route) =>
|
||||||
|
mergeRoute(layoutChildren, route as ClientRoute)
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
import { ComponentType } from 'react';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* routes
|
||||||
|
*/
|
||||||
|
export interface RouteConfig {
|
||||||
|
path: string;
|
||||||
|
component?: ComponentType;
|
||||||
|
routes?: RouteConfig[];
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* login module configuration
|
||||||
|
*/
|
||||||
|
export interface LoginPlugin {
|
||||||
|
shouldUseCustomLogin?: () => boolean;
|
||||||
|
CustomLoginComponent?: ComponentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* branding module configuration
|
||||||
|
*/
|
||||||
|
export interface BrandingPlugin {
|
||||||
|
ConfigPage?: ComponentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* localization configuration
|
||||||
|
*/
|
||||||
|
export interface LocalesConfig {
|
||||||
|
[locale: string]: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* application plugin interface
|
||||||
|
*/
|
||||||
|
export interface AppPlugin {
|
||||||
|
/**
|
||||||
|
* application initialization hook
|
||||||
|
* called when the application starts, can return initialization data
|
||||||
|
*/
|
||||||
|
onAppInit?: () => Promise<Record<string, any>> | Record<string, any>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* application ready hook
|
||||||
|
* called when the application is fully loaded
|
||||||
|
*/
|
||||||
|
onAppReady?: () => void | Promise<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* login module
|
||||||
|
*/
|
||||||
|
login?: LoginPlugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* branding module
|
||||||
|
*/
|
||||||
|
branding?: BrandingPlugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* localization configuration
|
||||||
|
*/
|
||||||
|
locales?: LocalesConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* routes extension
|
||||||
|
*/
|
||||||
|
routes?: RouteConfig[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* components extension
|
||||||
|
*/
|
||||||
|
components?: Record<string, ComponentType>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hooks extension
|
||||||
|
*/
|
||||||
|
hooks?: Record<string, (...args: unknown[]) => unknown>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* other custom fields for future extensions
|
||||||
|
*/
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* plugin manager interface
|
||||||
|
*/
|
||||||
|
export interface IPluginManager {
|
||||||
|
register(name: string, plugin: AppPlugin): void;
|
||||||
|
get(name: string): AppPlugin | undefined;
|
||||||
|
has(name: string): boolean;
|
||||||
|
getAll(): Map<string, AppPlugin>;
|
||||||
|
}
|
||||||
+2
-16
@@ -17,22 +17,8 @@
|
|||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./src/*"],
|
"@/*": ["./src/*"],
|
||||||
"@@/*": ["./src/.umi/*"],
|
"@@/*": ["./src/.umi/*"],
|
||||||
"@@test/*": ["./src/.umi-test/*"],
|
"@@test/*": ["./src/.umi-test/*"]
|
||||||
"@gpustack/core-ui": ["../core-ui/src/index.ts"],
|
|
||||||
"@gpustack/core-ui/*": ["../core-ui/src/*"],
|
|
||||||
"@gpustack/core-ui/hooks": ["../core-ui/src/lib/hooks"],
|
|
||||||
"@gpustack/core-ui/utils": ["../core-ui/src/lib/utils"],
|
|
||||||
"@gpustack/core-ui/types": ["../core-ui/src/lib/types"],
|
|
||||||
"@gpustack/core-ui/components": ["../core-ui/src/lib/components"],
|
|
||||||
"@gpustack/core-ui/lib/*": ["../core-ui/src/lib/*"]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": [
|
"include": ["./**/*.d.ts", "./**/*.ts", "./**/*.tsx"]
|
||||||
"./**/*.d.ts",
|
|
||||||
"./**/*.ts",
|
|
||||||
"./**/*.tsx",
|
|
||||||
"@gpustack/core-ui/lib/components/logs-viewer/parse-worker.ts",
|
|
||||||
"@gpustack/core-ui/lib/components/image-editor/invert-worker.ts",
|
|
||||||
"@gpustack/core-ui/lib/components/image-editor/offscreen-worker.ts"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user