feat: 添加MinIO文件系统支持并优化外部连接器功能
- 添加MinIO用户文件系统配置选项(BEAVER_MINIO_ROOT_USER等) - 更新外部连接器配置结构,包括BASE_URL和认证令牌设置 - 改进connector provider支持更多类型(official, feishu_bot等) - 实现Mistral模型推理模式支持reasoning_effort参数 - 增强外部连接器策略配置和运行时配置管理 - 添加connector bridge事件验证和安全保护机制 - 优化任务路由逻辑,区分simple_chat和new_task场景 - 更新初始技能工具提示配置,分离authoring admin功能
This commit is contained in:
@ -31,6 +31,7 @@ html,
|
||||
body {
|
||||
margin: 0;
|
||||
min-height: 100%;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
body {
|
||||
@ -56,7 +57,7 @@ select {
|
||||
|
||||
.portal-page {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
min-height: 100dvh;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
padding: 32px;
|
||||
@ -68,7 +69,7 @@ select {
|
||||
|
||||
.auth-page {
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
min-height: 100dvh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
@ -122,11 +123,11 @@ select {
|
||||
|
||||
.ghost-icon-button {
|
||||
position: absolute;
|
||||
right: 18px;
|
||||
right: 10px;
|
||||
top: 50%;
|
||||
z-index: 2;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
color: #a29d99;
|
||||
@ -203,6 +204,9 @@ select {
|
||||
|
||||
.login-footer a {
|
||||
justify-self: start;
|
||||
min-height: 44px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.portal-toolbar {
|
||||
@ -234,8 +238,8 @@ select {
|
||||
}
|
||||
|
||||
.language-switcher button {
|
||||
min-width: 34px;
|
||||
height: 28px;
|
||||
min-width: 44px;
|
||||
min-height: 44px;
|
||||
border: 0;
|
||||
border-radius: 999px;
|
||||
color: var(--zinc-600);
|
||||
@ -524,7 +528,7 @@ select {
|
||||
|
||||
.auth-page .auth-card.login-card {
|
||||
width: 100%;
|
||||
max-height: calc(100vh - clamp(48px, 10vh, 112px));
|
||||
max-height: calc(100dvh - clamp(48px, 10vh, 112px));
|
||||
padding: clamp(30px, 5vh, 54px) clamp(24px, 3.2vw, 44px) clamp(26px, 4vh, 40px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -578,6 +582,14 @@ select {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.auth-page .login-field-label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: var(--zinc-600);
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.auth-page .login-field input,
|
||||
.auth-page .login-field select {
|
||||
min-height: clamp(50px, 6vh, 60px);
|
||||
@ -680,7 +692,7 @@ select {
|
||||
.auth-page .auth-card.login-card {
|
||||
min-height: auto;
|
||||
padding: 34px 22px 28px;
|
||||
max-height: calc(100vh - 104px);
|
||||
max-height: calc(100dvh - 104px);
|
||||
}
|
||||
|
||||
.auth-page .login-logo {
|
||||
@ -722,3 +734,134 @@ select {
|
||||
padding: 24px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px) and (max-height: 700px) {
|
||||
.auth-page {
|
||||
padding: 76px 16px 12px;
|
||||
}
|
||||
|
||||
.auth-page .auth-card.login-card {
|
||||
max-height: calc(100dvh - 88px);
|
||||
padding: 20px 22px 18px;
|
||||
}
|
||||
|
||||
.auth-page .login-logo {
|
||||
width: 58px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.auth-page .auth-card.login-card h1 {
|
||||
margin-bottom: 14px;
|
||||
font-size: 23px;
|
||||
}
|
||||
|
||||
.auth-page .login-card .auth-form {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.auth-page .login-field-label {
|
||||
margin-bottom: 4px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.auth-page .login-field input,
|
||||
.auth-page .login-field select {
|
||||
min-height: 46px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.auth-page .login-card .primary-button {
|
||||
min-height: 48px;
|
||||
}
|
||||
|
||||
.auth-page .login-card .error-text {
|
||||
min-height: 18px;
|
||||
}
|
||||
|
||||
.auth-page .login-divider {
|
||||
margin: 12px 0 8px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.auth-page .login-footer {
|
||||
margin-top: 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-height: 520px) and (orientation: landscape) {
|
||||
.portal-page {
|
||||
display: block;
|
||||
min-height: 100dvh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.auth-page {
|
||||
min-height: 100dvh;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
padding: 52px 16px 6px;
|
||||
}
|
||||
|
||||
.auth-page .portal-panel {
|
||||
width: min(480px, 100%);
|
||||
}
|
||||
|
||||
.auth-page .auth-card.login-card {
|
||||
max-height: calc(100dvh - 64px);
|
||||
padding: 12px 22px 10px;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.auth-page .login-logo {
|
||||
width: 34px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.auth-page .auth-card.login-card h1 {
|
||||
margin-bottom: 4px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.auth-page .login-card .auth-form {
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.auth-page .login-field-label {
|
||||
margin-bottom: 2px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.auth-page .login-field input,
|
||||
.auth-page .login-field select {
|
||||
min-height: 44px;
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.auth-page .login-card .error-text {
|
||||
min-height: 14px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.auth-page .login-card .primary-button {
|
||||
min-height: 44px;
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.auth-page .login-divider {
|
||||
margin: 6px 0 4px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.auth-page .login-footer {
|
||||
margin-top: 0;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.portal-toolbar {
|
||||
top: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
import { useRef, useState } from 'react';
|
||||
|
||||
import { LanguageSwitcher } from '@/components/LanguageSwitcher';
|
||||
import { buildFrontendHandoffUrl, login, withNext } from '@/lib/auth-client';
|
||||
@ -20,6 +20,7 @@ export default function LoginPage() {
|
||||
const [showPassword, setShowPassword] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
const errorRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
@ -30,7 +31,14 @@ export default function LoginPage() {
|
||||
const response = await login(username, password);
|
||||
window.location.replace(buildFrontendHandoffUrl(response, nextPath));
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : pickPortalText(locale, '登录失败,请稍后重试', 'Sign-in failed. Please try again.'));
|
||||
const rawMessage = err instanceof Error ? err.message : '';
|
||||
const friendlyMessage = /401|Invalid credentials|用户名或密码/.test(rawMessage)
|
||||
? pickPortalText(locale, '用户名或密码错误,请检查后重试。', 'Username or password is incorrect. Please check and try again.')
|
||||
: pickPortalText(locale, '登录失败,请稍后重试。', 'Sign-in failed. Please try again.');
|
||||
setError(friendlyMessage);
|
||||
window.requestAnimationFrame(() => {
|
||||
errorRef.current?.focus();
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@ -56,7 +64,7 @@ export default function LoginPage() {
|
||||
|
||||
<form className="auth-form" onSubmit={handleSubmit}>
|
||||
<div className="field login-field">
|
||||
<label className="visually-hidden" htmlFor="username">{pickPortalText(locale, '用户名', 'Username')}</label>
|
||||
<label className="login-field-label" htmlFor="username">{pickPortalText(locale, '用户名', 'Username')}</label>
|
||||
<UserIcon />
|
||||
<input
|
||||
id="username"
|
||||
@ -69,7 +77,7 @@ export default function LoginPage() {
|
||||
</div>
|
||||
|
||||
<div className="field login-field">
|
||||
<label className="visually-hidden" htmlFor="password">{pickPortalText(locale, '密码', 'Password')}</label>
|
||||
<label className="login-field-label" htmlFor="password">{pickPortalText(locale, '密码', 'Password')}</label>
|
||||
<LockIcon />
|
||||
<input
|
||||
id="password"
|
||||
@ -90,9 +98,24 @@ export default function LoginPage() {
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="error-text">{error}</div>
|
||||
<div
|
||||
ref={errorRef}
|
||||
className="error-text"
|
||||
role={error ? 'alert' : undefined}
|
||||
aria-live="polite"
|
||||
tabIndex={error ? -1 : undefined}
|
||||
>
|
||||
{error}
|
||||
</div>
|
||||
|
||||
<button className="primary-button" type="submit" disabled={loading}>
|
||||
<button
|
||||
className="primary-button"
|
||||
type="submit"
|
||||
disabled={loading}
|
||||
aria-label={loading
|
||||
? pickPortalText(locale, '登录中', 'Signing in')
|
||||
: pickPortalText(locale, '登录', 'Sign in')}
|
||||
>
|
||||
{loading
|
||||
? pickPortalText(locale, '登录中...', 'Signing in...')
|
||||
: <ArrowRightIcon />}
|
||||
|
||||
4
auth-portal/src/test-results/.last-run.json
Normal file
4
auth-portal/src/test-results/.last-run.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"status": "failed",
|
||||
"failedTests": []
|
||||
}
|
||||
Reference in New Issue
Block a user