fix(style): global theme settings in login
This commit is contained in:
@@ -0,0 +1,20 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="1920" height="1080">
|
||||||
|
<filter id="noiseFilter">
|
||||||
|
<feTurbulence
|
||||||
|
type="fractalNoise"
|
||||||
|
baseFrequency="0.6"
|
||||||
|
numOctaves="2"
|
||||||
|
stitchTiles="stitch"
|
||||||
|
/>
|
||||||
|
<feColorMatrix
|
||||||
|
type="matrix"
|
||||||
|
values="1 0 0 0 0
|
||||||
|
0 1 0 0 0
|
||||||
|
0 0 1 0 0
|
||||||
|
0 0 0 0.2 0" />
|
||||||
|
<feGaussianBlur stdDeviation="0.6" />
|
||||||
|
</filter>
|
||||||
|
<rect width="100%" height="100%" fill="#181818"/>
|
||||||
|
<rect width="100%" height="100%" filter="url(#noiseFilter)"/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 546 B |
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" ?>
|
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="500" height="500">
|
|
||||||
<filter id="n" x="0" y="0">
|
|
||||||
<feTurbulence type="fractalNoise" baseFrequency="0.65" numOctaves="5" stitchTiles="stitch"/>
|
|
||||||
</filter>
|
|
||||||
<rect width="500" height="500" fill="#1f1f1f" opacity="0.4"/>
|
|
||||||
<rect width="500" height="500" filter="url(#n)" opacity="0.09"/>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 366 B |
@@ -5,7 +5,7 @@ import { atomWithStorage } from 'jotai/utils';
|
|||||||
type UserSettings = {
|
type UserSettings = {
|
||||||
theme: 'light' | 'realDark' | 'auto';
|
theme: 'light' | 'realDark' | 'auto';
|
||||||
colorPrimary: string;
|
colorPrimary: string;
|
||||||
isDarkTheme?: boolean;
|
isDarkTheme: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const userSettingsAtom = atomWithStorage<UserSettings>('userSettings', {
|
export const userSettingsAtom = atomWithStorage<UserSettings>('userSettings', {
|
||||||
|
|||||||
@@ -4,10 +4,28 @@ import VersionInfo, { modalConfig } from '@/components/version-info';
|
|||||||
import externalLinks from '@/constants/external-links';
|
import externalLinks from '@/constants/external-links';
|
||||||
import { useIntl } from '@umijs/max';
|
import { useIntl } from '@umijs/max';
|
||||||
import { Button, Modal, Space } from 'antd';
|
import { Button, Modal, Space } from 'antd';
|
||||||
import './index.less';
|
import { createStyles } from 'antd-style';
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ token, css }) => ({
|
||||||
|
footer: css`
|
||||||
|
bottom: 0;
|
||||||
|
width: 100%;
|
||||||
|
background-color: transparent;
|
||||||
|
padding: 20px 0;
|
||||||
|
text-align: center;
|
||||||
|
font-size: var(--font-size-middle);
|
||||||
|
color: ${token.colorTextTertiary};
|
||||||
|
`,
|
||||||
|
'footer-content-left-text': {
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center'
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
const Footer: React.FC = () => {
|
const Footer: React.FC = () => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
const { styles } = useStyles();
|
||||||
|
|
||||||
const showVersion = () => {
|
const showVersion = () => {
|
||||||
Modal.info({
|
Modal.info({
|
||||||
@@ -18,10 +36,10 @@ const Footer: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="footer">
|
<div className={styles.footer}>
|
||||||
<div className="footer-content">
|
<div className="footer-content">
|
||||||
<div className="footer-content-left">
|
<div className="footer-content-left">
|
||||||
<div className="footer-content-left-text">
|
<div className={styles['footer-content-left-text']}>
|
||||||
<Space size={4}>
|
<Space size={4}>
|
||||||
<span>©</span>
|
<span>©</span>
|
||||||
<span> {new Date().getFullYear()}</span>
|
<span> {new Date().getFullYear()}</span>
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import useUserSettings from '@/hooks/use-user-settings';
|
||||||
|
import { MoonOutlined, SunOutlined } from '@ant-design/icons';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ token, css }) => ({
|
||||||
|
wrapper: css`
|
||||||
|
display: inline-flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
color: ${token.colorText};
|
||||||
|
font-size: var(--font-size-base);
|
||||||
|
padding: 0 8px;
|
||||||
|
gap: 8px;
|
||||||
|
&:hover {
|
||||||
|
color: ${token.colorTextTertiary};
|
||||||
|
}
|
||||||
|
.anticon {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}));
|
||||||
|
|
||||||
|
const ThemeToggle: React.FC = () => {
|
||||||
|
const { setTheme, userSettings } = useUserSettings();
|
||||||
|
const { styles } = useStyles();
|
||||||
|
|
||||||
|
const handleChangeTheme = () => {
|
||||||
|
const currentTheme =
|
||||||
|
userSettings.theme === 'realDark' ? 'light' : 'realDark';
|
||||||
|
setTheme(currentTheme);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.wrapper} onClick={handleChangeTheme}>
|
||||||
|
{userSettings.theme === 'realDark' ? <MoonOutlined /> : <SunOutlined />}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ThemeToggle;
|
||||||
@@ -2,6 +2,7 @@ import dark from './dark';
|
|||||||
import light from './light';
|
import light from './light';
|
||||||
|
|
||||||
export const colorPrimary = '#007BFF';
|
export const colorPrimary = '#007BFF';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
light,
|
light,
|
||||||
dark,
|
dark,
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ html {
|
|||||||
--color-fill-spin-bg: rgba(255, 255, 255, 60%);
|
--color-fill-spin-bg: rgba(255, 255, 255, 60%);
|
||||||
--width-tooltip-max: 300px;
|
--width-tooltip-max: 300px;
|
||||||
--color-bg-tooltip: '#fff';
|
--color-bg-tooltip: '#fff';
|
||||||
|
--color-modal-content-bg: rgba(255, 255, 255, 90%);
|
||||||
// ======== input ============
|
// ======== input ============
|
||||||
--box-shadow-base: 0 4px 6px rgba(227, 232, 240, 70%);
|
--box-shadow-base: 0 4px 6px rgba(227, 232, 240, 70%);
|
||||||
--ant-border-radius-lg: 4px;
|
--ant-border-radius-lg: 4px;
|
||||||
@@ -93,6 +94,7 @@ html[data-theme='realDark'] {
|
|||||||
--color-bg-tooltip: #424242;
|
--color-bg-tooltip: #424242;
|
||||||
--color-editor-header-bg: #292929;
|
--color-editor-header-bg: #292929;
|
||||||
--color-progress-text: rgba(255, 255, 255, 80%);
|
--color-progress-text: rgba(255, 255, 255, 80%);
|
||||||
|
--color-modal-content-bg: #1f1f1f;
|
||||||
|
|
||||||
background: #141414;
|
background: #141414;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,6 +132,7 @@ const AddModal: FC<AddModalProps> = (props) => {
|
|||||||
}
|
}
|
||||||
return categories || null;
|
return categories || null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSelectModelFile = (item: any, evaluate?: boolean) => {
|
const handleSelectModelFile = (item: any, evaluate?: boolean) => {
|
||||||
form.current?.form?.resetFields(resetFields);
|
form.current?.form?.resetFields(resetFields);
|
||||||
const modelInfo = onSelectModel(selectedModel, props.source);
|
const modelInfo = onSelectModel(selectedModel, props.source);
|
||||||
@@ -142,7 +143,11 @@ const AddModal: FC<AddModalProps> = (props) => {
|
|||||||
categories: getCategory(item)
|
categories: getCategory(item)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (item.fakeName) {
|
if (
|
||||||
|
item.fakeName &&
|
||||||
|
!isHolderRef.current.model &&
|
||||||
|
!isHolderRef.current.file
|
||||||
|
) {
|
||||||
handleShowCompatibleAlert(item.evaluateResult);
|
handleShowCompatibleAlert(item.evaluateResult);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -153,7 +158,9 @@ const AddModal: FC<AddModalProps> = (props) => {
|
|||||||
setIsGGUF(false);
|
setIsGGUF(false);
|
||||||
form.current?.form?.resetFields(resetFields);
|
form.current?.form?.resetFields(resetFields);
|
||||||
const modelInfo = onSelectModel(item, props.source);
|
const modelInfo = onSelectModel(item, props.source);
|
||||||
|
if (!isHolderRef.current.model) {
|
||||||
handleShowCompatibleAlert(item.evaluateResult);
|
handleShowCompatibleAlert(item.evaluateResult);
|
||||||
|
}
|
||||||
form.current?.setFieldsValue?.({
|
form.current?.setFieldsValue?.({
|
||||||
...getDefaultSpec(item),
|
...getDefaultSpec(item),
|
||||||
...modelInfo,
|
...modelInfo,
|
||||||
@@ -256,7 +263,15 @@ const AddModal: FC<AddModalProps> = (props) => {
|
|||||||
const displayEvaluateStatus = (data: {
|
const displayEvaluateStatus = (data: {
|
||||||
show?: boolean;
|
show?: boolean;
|
||||||
flag: Record<string, boolean>;
|
flag: Record<string, boolean>;
|
||||||
}) => {};
|
}) => {
|
||||||
|
setIsHolderRef(data.flag);
|
||||||
|
setWarningStatus({
|
||||||
|
show: isHolderRef.current.model || isHolderRef.current.file,
|
||||||
|
title: '',
|
||||||
|
type: 'transition',
|
||||||
|
message: intl.formatMessage({ id: 'models.form.evaluating' })
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (open) {
|
if (open) {
|
||||||
|
|||||||
@@ -28,7 +28,6 @@
|
|||||||
.mkd-title {
|
.mkd-title {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background-color: var(--ant-color-fill-tertiary);
|
background-color: var(--ant-color-fill-tertiary);
|
||||||
border-bottom: 1px solid rgba(255, 255, 255, 10%);
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import LogoIcon from '@/assets/images/gpustack-logo.png';
|
|||||||
import { initialPasswordAtom, userAtom } from '@/atoms/user';
|
import { initialPasswordAtom, userAtom } from '@/atoms/user';
|
||||||
import LangSelect from '@/components/lang-select';
|
import LangSelect from '@/components/lang-select';
|
||||||
import SealInput from '@/components/seal-form/seal-input';
|
import SealInput from '@/components/seal-form/seal-input';
|
||||||
|
import ThemeToggle from '@/components/theme-toggle';
|
||||||
import {
|
import {
|
||||||
CRYPT_TEXT,
|
CRYPT_TEXT,
|
||||||
REMEMBER_ME_KEY,
|
REMEMBER_ME_KEY,
|
||||||
@@ -12,6 +13,7 @@ import {
|
|||||||
import { LockOutlined, UserOutlined } from '@ant-design/icons';
|
import { LockOutlined, UserOutlined } from '@ant-design/icons';
|
||||||
import { useIntl, useModel } from '@umijs/max';
|
import { useIntl, useModel } from '@umijs/max';
|
||||||
import { Button, Checkbox, Form } from 'antd';
|
import { Button, Checkbox, Form } from 'antd';
|
||||||
|
import { createStyles } from 'antd-style';
|
||||||
import CryptoJS from 'crypto-js';
|
import CryptoJS from 'crypto-js';
|
||||||
import { useAtom } from 'jotai';
|
import { useAtom } from 'jotai';
|
||||||
import { useEffect, useMemo } from 'react';
|
import { useEffect, useMemo } from 'react';
|
||||||
@@ -19,7 +21,26 @@ import { flushSync } from 'react-dom';
|
|||||||
import { login } from '../apis';
|
import { login } from '../apis';
|
||||||
import { checkDefaultPage } from '../utils';
|
import { checkDefaultPage } from '../utils';
|
||||||
|
|
||||||
|
const useStyles = createStyles(({ token, css }) => ({
|
||||||
|
header: css`
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
position: fixed;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
padding: 20px;
|
||||||
|
.anticon-global {
|
||||||
|
color: ${token.colorText};
|
||||||
|
}
|
||||||
|
.anticon:hover {
|
||||||
|
color: ${token.colorTextTertiary};
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}));
|
||||||
|
|
||||||
const LoginForm = () => {
|
const LoginForm = () => {
|
||||||
|
const { styles } = useStyles();
|
||||||
const [userInfo, setUserInfo] = useAtom(userAtom);
|
const [userInfo, setUserInfo] = useAtom(userAtom);
|
||||||
const [initialPassword, setInitialPassword] = useAtom(initialPasswordAtom);
|
const [initialPassword, setInitialPassword] = useAtom(initialPasswordAtom);
|
||||||
const { initialState, setInitialState } = useModel('@@initialState') || {};
|
const { initialState, setInitialState } = useModel('@@initialState') || {};
|
||||||
@@ -130,14 +151,8 @@ const LoginForm = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div className={styles.header}>
|
||||||
style={{
|
<ThemeToggle></ThemeToggle>
|
||||||
position: 'fixed',
|
|
||||||
right: 0,
|
|
||||||
top: 0,
|
|
||||||
padding: '20px'
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<LangSelect />
|
<LangSelect />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
+12
-13
@@ -11,7 +11,7 @@ import LoginForm from './components/login-form';
|
|||||||
import PasswordForm from './components/password-form';
|
import PasswordForm from './components/password-form';
|
||||||
import { checkDefaultPage } from './utils';
|
import { checkDefaultPage } from './utils';
|
||||||
|
|
||||||
const Wrapper = styled.div`
|
const Wrapper = styled.div<{ $isDarkTheme: boolean }>`
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
@@ -19,9 +19,11 @@ const Wrapper = styled.div`
|
|||||||
right: 0;
|
right: 0;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
z-index: -1;
|
z-index: -1;
|
||||||
background: url(${Bg2}) center center no-repeat;
|
background: ${({ $isDarkTheme }) =>
|
||||||
background-size: cover;
|
$isDarkTheme
|
||||||
opacity: 0.6;
|
? `repeating-linear-gradient(45deg, #000, transparent 120px)`
|
||||||
|
: `url(${Bg2}) center center /cover no-repeat`};
|
||||||
|
opacity: ${({ $isDarkTheme }) => ($isDarkTheme ? 1 : 0.6)};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Box = styled.div`
|
const Box = styled.div`
|
||||||
@@ -38,7 +40,7 @@ const FormWrapper = styled.div`
|
|||||||
width: max-content;
|
width: max-content;
|
||||||
height: max-content;
|
height: max-content;
|
||||||
padding: 32px;
|
padding: 32px;
|
||||||
background-color: var(--ant-modal-content-bg);
|
background-color: var(--color-modal-content-bg);
|
||||||
|
|
||||||
.field-wrapper {
|
.field-wrapper {
|
||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
@@ -50,15 +52,10 @@ const FormWrapper = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const Login = () => {
|
const Login = () => {
|
||||||
const { themeData, userSettings } = useUserSettings();
|
const { themeData, userSettings, isDarkTheme } = useUserSettings();
|
||||||
const { token } = theme.useToken();
|
|
||||||
const [userInfo, setUserInfo] = useAtom(userAtom);
|
const [userInfo, setUserInfo] = useAtom(userAtom);
|
||||||
const { initialState, setInitialState } = useModel('@@initialState') || {};
|
const { initialState, setInitialState } = useModel('@@initialState') || {};
|
||||||
|
|
||||||
const globalCssvars: Record<string, any> = {
|
|
||||||
'--ant-modal-content-bg': 'rgba(255, 255, 255, 0.9)'
|
|
||||||
};
|
|
||||||
|
|
||||||
const gotoDefaultPage = async (userInfo: any) => {
|
const gotoDefaultPage = async (userInfo: any) => {
|
||||||
if (!userInfo || userInfo?.require_password_change) {
|
if (!userInfo || userInfo?.require_password_change) {
|
||||||
return;
|
return;
|
||||||
@@ -72,9 +69,11 @@ const Login = () => {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
gotoDefaultPage(userInfo);
|
gotoDefaultPage(userInfo);
|
||||||
}, [userInfo]);
|
}, [userInfo]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = 'GPUStack';
|
document.title = 'GPUStack';
|
||||||
}, []);
|
}, []);
|
||||||
@@ -90,8 +89,8 @@ const Login = () => {
|
|||||||
...themeData
|
...themeData
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={globalCssvars}>
|
<div>
|
||||||
<Wrapper></Wrapper>
|
<Wrapper $isDarkTheme={isDarkTheme}></Wrapper>
|
||||||
<Box>
|
<Box>
|
||||||
<FormWrapper>
|
<FormWrapper>
|
||||||
{userInfo?.require_password_change ? (
|
{userInfo?.require_password_change ? (
|
||||||
|
|||||||
@@ -158,15 +158,7 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
..._.omitBy(
|
..._.omitBy(finalParameters, (value: string) => !value),
|
||||||
parameters,
|
|
||||||
(value: string, key: string) =>
|
|
||||||
!value || ['width', 'height', 'seed'].includes(key)
|
|
||||||
),
|
|
||||||
size:
|
|
||||||
parameters.size === 'custom'
|
|
||||||
? `${parameters.width}x${parameters.height}`
|
|
||||||
: parameters.size,
|
|
||||||
seed: parameters.random_seed ? generateRandomNumber() : parameters.seed,
|
seed: parameters.random_seed ? generateRandomNumber() : parameters.seed,
|
||||||
stream: true,
|
stream: true,
|
||||||
stream_options: {
|
stream_options: {
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ const GroundImages: React.FC<MessageProps> = forwardRef((props, ref) => {
|
|||||||
prompt: currentPrompt
|
prompt: currentPrompt
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, [finalParameters, currentPrompt, parameters.size]);
|
}, [finalParameters, currentPrompt, isOpenaiCompatible]);
|
||||||
|
|
||||||
const handleClear = () => {
|
const handleClear = () => {
|
||||||
setCurrentPrompt('');
|
setCurrentPrompt('');
|
||||||
|
|||||||
@@ -1,135 +0,0 @@
|
|||||||
import FormButtons from '@/components/form-buttons';
|
|
||||||
import SealInput from '@/components/seal-form/seal-input';
|
|
||||||
import { PasswordReg } from '@/config';
|
|
||||||
import { INPUT_WIDTH } from '@/constants';
|
|
||||||
import { updatePassword } from '@/pages/login/apis';
|
|
||||||
import { PageContainer } from '@ant-design/pro-components';
|
|
||||||
import { useIntl } from '@umijs/max';
|
|
||||||
import { Form, message } from 'antd';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
interface ProfileProps {
|
|
||||||
username?: string;
|
|
||||||
new_password: string;
|
|
||||||
current_password: string;
|
|
||||||
}
|
|
||||||
const Profile: React.FC = () => {
|
|
||||||
const [form] = Form.useForm();
|
|
||||||
const intl = useIntl();
|
|
||||||
|
|
||||||
const handleOnFinish = async (values: any) => {
|
|
||||||
try {
|
|
||||||
await updatePassword({
|
|
||||||
new_password: values.new_password,
|
|
||||||
current_password: values.current_password
|
|
||||||
});
|
|
||||||
message.success(intl.formatMessage({ id: 'common.message.success' }));
|
|
||||||
} catch (error) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleOnFinishFailed = (errorInfo: any) => {
|
|
||||||
console.log('handleOnFinishFailed', errorInfo);
|
|
||||||
};
|
|
||||||
const handleCancel = () => {
|
|
||||||
form.resetFields();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<PageContainer
|
|
||||||
ghost
|
|
||||||
header={{
|
|
||||||
title: intl.formatMessage({ id: 'users.form.updatepassword' }),
|
|
||||||
style: {
|
|
||||||
paddingInline: 'var(--layout-content-header-inlinepadding)'
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
extra={[]}
|
|
||||||
>
|
|
||||||
<Form
|
|
||||||
style={{ width: '524px' }}
|
|
||||||
name="profileForm"
|
|
||||||
form={form}
|
|
||||||
onFinish={handleOnFinish}
|
|
||||||
onFinishFailed={handleOnFinishFailed}
|
|
||||||
>
|
|
||||||
<Form.Item<ProfileProps>
|
|
||||||
name="current_password"
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: intl.formatMessage(
|
|
||||||
{ id: 'common.form.rule.input' },
|
|
||||||
{
|
|
||||||
name: intl.formatMessage({
|
|
||||||
id: 'users.form.currentpassword'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<SealInput.Password
|
|
||||||
label={intl.formatMessage({ id: 'users.form.currentpassword' })}
|
|
||||||
required
|
|
||||||
style={{ width: INPUT_WIDTH.default }}
|
|
||||||
></SealInput.Password>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item<ProfileProps>
|
|
||||||
name="new_password"
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
pattern: PasswordReg,
|
|
||||||
message: intl.formatMessage({
|
|
||||||
id: 'users.form.rule.password'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<SealInput.Password
|
|
||||||
label={intl.formatMessage({ id: 'users.form.newpassword' })}
|
|
||||||
required
|
|
||||||
style={{ width: INPUT_WIDTH.default }}
|
|
||||||
></SealInput.Password>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
name="confirm_password"
|
|
||||||
dependencies={['new_password']}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: intl.formatMessage({
|
|
||||||
id: 'users.password.confirm.empty'
|
|
||||||
})
|
|
||||||
},
|
|
||||||
({ getFieldValue }) => ({
|
|
||||||
validator(_, value) {
|
|
||||||
if (!value || getFieldValue('new_password') === value) {
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
return Promise.reject(
|
|
||||||
new Error(
|
|
||||||
intl.formatMessage({ id: 'users.password.confirm.error' })
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<SealInput.Password
|
|
||||||
required={true}
|
|
||||||
style={{ width: INPUT_WIDTH.default }}
|
|
||||||
label={intl.formatMessage({ id: 'users.password.confirm' })}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
<FormButtons
|
|
||||||
htmlType="submit"
|
|
||||||
onCancel={handleCancel}
|
|
||||||
showCancel={false}
|
|
||||||
></FormButtons>
|
|
||||||
</Form>
|
|
||||||
</PageContainer>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default Profile;
|
|
||||||
@@ -17,14 +17,18 @@ const ThemeOptions = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
const Appearance: React.FC = () => {
|
const Appearance: React.FC = () => {
|
||||||
const { setTheme } = useUserSettings();
|
const { setTheme, userSettings } = useUserSettings();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const handleOnChange = (e: any) => {
|
const handleOnChange = (e: any) => {
|
||||||
setTheme(e.target.value);
|
setTheme(e.target.value);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<Radio.Group onChange={handleOnChange} style={{ marginTop: 16 }}>
|
<Radio.Group
|
||||||
|
onChange={handleOnChange}
|
||||||
|
style={{ marginTop: 16 }}
|
||||||
|
value={userSettings.theme}
|
||||||
|
>
|
||||||
{ThemeOptions.map((item) => (
|
{ThemeOptions.map((item) => (
|
||||||
<Radio key={item.key} value={item.key}>
|
<Radio key={item.key} value={item.key}>
|
||||||
{intl.formatMessage({ id: item.label })}
|
{intl.formatMessage({ id: item.label })}
|
||||||
|
|||||||
@@ -546,6 +546,9 @@ const ModelFiles = () => {
|
|||||||
{
|
{
|
||||||
title: intl.formatMessage({ id: 'models.form.source' }),
|
title: intl.formatMessage({ id: 'models.form.source' }),
|
||||||
dataIndex: 'source',
|
dataIndex: 'source',
|
||||||
|
ellipsis: {
|
||||||
|
showTitle: false
|
||||||
|
},
|
||||||
render: (text: string, record: ListItem) => {
|
render: (text: string, record: ListItem) => {
|
||||||
const modelInfo = getModelInfo(record);
|
const modelInfo = getModelInfo(record);
|
||||||
const { repo_id } = modelInfo;
|
const { repo_id } = modelInfo;
|
||||||
@@ -561,6 +564,9 @@ const ModelFiles = () => {
|
|||||||
{
|
{
|
||||||
title: 'Worker',
|
title: 'Worker',
|
||||||
dataIndex: 'worker_name',
|
dataIndex: 'worker_name',
|
||||||
|
ellipsis: {
|
||||||
|
showTitle: false
|
||||||
|
},
|
||||||
render: (text: string, record: ListItem) => {
|
render: (text: string, record: ListItem) => {
|
||||||
return (
|
return (
|
||||||
<AutoTooltip ghost>
|
<AutoTooltip ghost>
|
||||||
@@ -581,6 +587,9 @@ const ModelFiles = () => {
|
|||||||
title: intl.formatMessage({ id: 'resources.modelfiles.form.path' }),
|
title: intl.formatMessage({ id: 'resources.modelfiles.form.path' }),
|
||||||
dataIndex: 'resolved_paths',
|
dataIndex: 'resolved_paths',
|
||||||
width: '35%',
|
width: '35%',
|
||||||
|
ellipsis: {
|
||||||
|
showTitle: false
|
||||||
|
},
|
||||||
render: (text: string, record: ListItem) => (
|
render: (text: string, record: ListItem) => (
|
||||||
<ResolvedPathColumn record={record} />
|
<ResolvedPathColumn record={record} />
|
||||||
)
|
)
|
||||||
@@ -588,10 +597,12 @@ const ModelFiles = () => {
|
|||||||
{
|
{
|
||||||
title: intl.formatMessage({ id: 'resources.modelfiles.size' }),
|
title: intl.formatMessage({ id: 'resources.modelfiles.size' }),
|
||||||
dataIndex: 'size',
|
dataIndex: 'size',
|
||||||
width: 100,
|
ellipsis: {
|
||||||
|
showTitle: false
|
||||||
|
},
|
||||||
render: (text: string, record: ListItem) => {
|
render: (text: string, record: ListItem) => {
|
||||||
return (
|
return (
|
||||||
<AutoTooltip ghost maxWidth={100}>
|
<AutoTooltip ghost>
|
||||||
<span>{convertFileSize(record.size, 1, true)}</span>
|
<span>{convertFileSize(record.size, 1, true)}</span>
|
||||||
</AutoTooltip>
|
</AutoTooltip>
|
||||||
);
|
);
|
||||||
@@ -601,9 +612,11 @@ const ModelFiles = () => {
|
|||||||
title: intl.formatMessage({ id: 'common.table.createTime' }),
|
title: intl.formatMessage({ id: 'common.table.createTime' }),
|
||||||
dataIndex: 'created_at',
|
dataIndex: 'created_at',
|
||||||
sorter: false,
|
sorter: false,
|
||||||
width: 180,
|
ellipsis: {
|
||||||
|
showTitle: false
|
||||||
|
},
|
||||||
render: (text: number) => (
|
render: (text: number) => (
|
||||||
<AutoTooltip ghost>
|
<AutoTooltip ghost minWidth={20}>
|
||||||
{dayjs(text).format('YYYY-MM-DD HH:mm:ss')}
|
{dayjs(text).format('YYYY-MM-DD HH:mm:ss')}
|
||||||
</AutoTooltip>
|
</AutoTooltip>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user