mirror of
https://github.com/eigent-ai/eigent.git
synced 2026-05-19 16:31:36 +00:00
fix: patch help_improve bug (#1455)
Co-authored-by: Wendong-Fan <133094783+Wendong-Fan@users.noreply.github.com>
This commit is contained in:
parent
1d6a8550e0
commit
737bd1eaeb
5 changed files with 135 additions and 51 deletions
|
|
@ -77,7 +77,7 @@ def get_privacy(session: Session = Depends(session), auth: Auth = Depends(auth_m
|
|||
return UserPrivacySettings.default_settings()
|
||||
|
||||
logger.debug("Privacy settings retrieved", extra={"user_id": user_id})
|
||||
return model.pricacy_setting
|
||||
return UserPrivacySettings(**model.pricacy_setting).to_response()
|
||||
|
||||
|
||||
@router.put("/user/privacy", name="update user privacy")
|
||||
|
|
@ -97,7 +97,7 @@ def put_privacy(data: UserPrivacySettings, session: Session = Depends(session),
|
|||
model.save(session)
|
||||
logger.info("Privacy settings created", extra={"user_id": user_id})
|
||||
|
||||
return model.pricacy_setting
|
||||
return UserPrivacySettings(**model.pricacy_setting).to_response()
|
||||
|
||||
|
||||
@router.get("/user/current_credits", name="get user current credits")
|
||||
|
|
|
|||
|
|
@ -1,16 +1,18 @@
|
|||
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
|
||||
|
||||
from typing import ClassVar
|
||||
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy import JSON
|
||||
|
|
@ -31,6 +33,21 @@ class UserPrivacySettings(BaseModel):
|
|||
access_your_address: bool | None = False
|
||||
password_storage: bool | None = False
|
||||
|
||||
# Fields that must all be True for the user to proceed
|
||||
REQUIRED_FIELDS: ClassVar[list[str]] = [
|
||||
'take_screenshot',
|
||||
'access_local_software',
|
||||
'access_your_address',
|
||||
'password_storage',
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def default_settings(cls) -> dict:
|
||||
return cls().model_dump()
|
||||
instance = cls()
|
||||
return {**instance.model_dump(), "all_required_granted": instance.all_required_granted()}
|
||||
|
||||
def all_required_granted(self) -> bool:
|
||||
return all(getattr(self, f) for f in self.REQUIRED_FIELDS)
|
||||
|
||||
def to_response(self) -> dict:
|
||||
return {**self.model_dump(), "all_required_granted": self.all_required_granted()}
|
||||
|
|
|
|||
80
server/tests/user.http
Normal file
80
server/tests/user.http
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
### ============================================
|
||||
### Eigent Server API Tests
|
||||
### ============================================
|
||||
### VSCode Extension: "REST Client" by Huachao Mao
|
||||
### Extension ID: humao.rest-client
|
||||
### ============================================
|
||||
|
||||
@baseUrl = http://localhost:3001/api
|
||||
@token = YOUR_TOKEN_HERE
|
||||
|
||||
### ──────────────────────────────────────────
|
||||
### Auth (no token required)
|
||||
### ──────────────────────────────────────────
|
||||
|
||||
### Register a new user
|
||||
POST {{baseUrl}}/register
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"email": "test@example.com",
|
||||
"password": "testpassword123"
|
||||
}
|
||||
|
||||
### Login
|
||||
# @name login
|
||||
POST {{baseUrl}}/login
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"email": "test@example.com",
|
||||
"password": "testpassword123"
|
||||
}
|
||||
|
||||
### Save token from login response (use this after running login)
|
||||
@authToken = {{login.response.body.token}}
|
||||
|
||||
### ──────────────────────────────────────────
|
||||
### User
|
||||
### ──────────────────────────────────────────
|
||||
|
||||
### Get current user info
|
||||
GET {{baseUrl}}/user
|
||||
Authorization: Bearer {{authToken}}
|
||||
|
||||
### ──────────────────────────────────────────
|
||||
### Privacy Settings
|
||||
### ──────────────────────────────────────────
|
||||
|
||||
### Get privacy settings
|
||||
GET {{baseUrl}}/user/privacy
|
||||
Authorization: Bearer {{authToken}}
|
||||
|
||||
### Update privacy settings
|
||||
PUT {{baseUrl}}/user/privacy
|
||||
Authorization: Bearer {{authToken}}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"take_screenshot": true,
|
||||
"access_local_software": false,
|
||||
"access_your_address": false,
|
||||
"password_storage": false
|
||||
}
|
||||
|
||||
### Update only help_improve
|
||||
PUT {{baseUrl}}/user/privacy
|
||||
Authorization: Bearer {{authToken}}
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"help_improve": true
|
||||
}
|
||||
|
||||
### ──────────────────────────────────────────
|
||||
### User Stats
|
||||
### ──────────────────────────────────────────
|
||||
|
||||
### Get user stats
|
||||
GET {{baseUrl}}/user/stat
|
||||
Authorization: Bearer {{authToken}}
|
||||
|
|
@ -65,14 +65,7 @@ export default function ChatBox(): JSX.Element {
|
|||
useEffect(() => {
|
||||
proxyFetchGet('/api/user/privacy')
|
||||
.then((res) => {
|
||||
let _privacy = 0;
|
||||
Object.keys(res).forEach((key) => {
|
||||
if (!res[key]) {
|
||||
_privacy++;
|
||||
return;
|
||||
}
|
||||
});
|
||||
setPrivacy(_privacy === 0 ? true : false);
|
||||
setPrivacy(res.all_required_granted);
|
||||
})
|
||||
.catch((err) => console.error('Failed to fetch settings:', err));
|
||||
|
||||
|
|
@ -989,7 +982,7 @@ export default function ChatBox(): JSX.Element {
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="rounded-2xl border-border-tertiary bg-surface-secondary h-full w-full flex-none items-center justify-center overflow-hidden border-solid">
|
||||
<div className="h-full w-full flex-none items-center justify-center overflow-hidden rounded-2xl border-solid border-border-tertiary bg-surface-secondary">
|
||||
{/* Unified ChatBox Structure */}
|
||||
<div className="relative flex h-full w-full flex-col overflow-hidden">
|
||||
{/* Header Box - Always visible */}
|
||||
|
|
@ -1006,10 +999,10 @@ export default function ChatBox(): JSX.Element {
|
|||
<div className="relative flex flex-1 flex-col overflow-hidden">
|
||||
{/* Project Chat Container - Show when has messages (absolute, full height) */}
|
||||
<div
|
||||
className={`inset-0 ease-in-out absolute flex h-full flex-col transition-all duration-300 ${
|
||||
className={`absolute inset-0 flex h-full flex-col transition-all duration-300 ease-in-out ${
|
||||
hasAnyMessages
|
||||
? 'translate-y-0 pointer-events-auto opacity-100'
|
||||
: '-translate-y-4 pointer-events-none opacity-0'
|
||||
? 'pointer-events-auto translate-y-0 opacity-100'
|
||||
: 'pointer-events-none -translate-y-4 opacity-0'
|
||||
}`}
|
||||
>
|
||||
<ProjectChatContainer
|
||||
|
|
@ -1020,15 +1013,15 @@ export default function ChatBox(): JSX.Element {
|
|||
|
||||
{/* Init State Container - Welcome + BottomBox + Suggestions (vertically centered) */}
|
||||
<div
|
||||
className={`ease-in-out flex flex-1 flex-col transition-all duration-300 ${
|
||||
className={`flex flex-1 flex-col transition-all duration-300 ease-in-out ${
|
||||
hasAnyMessages
|
||||
? 'inset-0 pointer-events-none absolute opacity-0'
|
||||
? 'pointer-events-none absolute inset-0 opacity-0'
|
||||
: 'pointer-events-auto opacity-100'
|
||||
}`}
|
||||
>
|
||||
{/* Welcome Message - Top area, flex-1 to push content down */}
|
||||
<div className="gap-1 pb-4 flex flex-1 flex-col items-center justify-end">
|
||||
<div className="text-body-lg font-bold text-text-heading text-center">
|
||||
<div className="flex flex-1 flex-col items-center justify-end gap-1 pb-4">
|
||||
<div className="text-center text-body-lg font-bold text-text-heading">
|
||||
{t('layout.welcome-to-eigent')}
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1067,24 +1060,24 @@ export default function ChatBox(): JSX.Element {
|
|||
)}
|
||||
|
||||
{/* Suggestion Area - Bottom area, flex-1 to push content up */}
|
||||
<div className="mt-3 gap-2 flex h-[210px] flex-1 items-start justify-center">
|
||||
<div className="mt-3 flex h-[210px] flex-1 items-start justify-center gap-2">
|
||||
{!hasModel ? (
|
||||
<div className="gap-2 flex items-center">
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
onClick={() => {
|
||||
navigate('/history?tab=agents');
|
||||
}}
|
||||
className="gap-2 rounded-md bg-surface-warning px-sm py-xs flex cursor-pointer items-center"
|
||||
className="flex cursor-pointer items-center gap-2 rounded-md bg-surface-warning px-sm py-xs"
|
||||
>
|
||||
<TriangleAlert size={20} className="text-icon-warning" />
|
||||
<span className="text-xs font-medium text-text-warning flex-1 leading-[20px]">
|
||||
<span className="flex-1 text-xs font-medium leading-[20px] text-text-warning">
|
||||
{t('layout.please-select-model')}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
{hasModel && !privacy ? (
|
||||
<div className="gap-2 flex items-center">
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
onClick={(e) => {
|
||||
const target = e.target as HTMLElement;
|
||||
|
|
@ -1106,13 +1099,13 @@ export default function ChatBox(): JSX.Element {
|
|||
proxyFetchPut('/api/user/privacy', requestData);
|
||||
setPrivacy(true);
|
||||
}}
|
||||
className="gap-1 rounded-md bg-surface-information px-sm py-xs flex cursor-pointer items-center"
|
||||
className="flex cursor-pointer items-center gap-1 rounded-md bg-surface-information px-sm py-xs"
|
||||
>
|
||||
<TriangleAlert
|
||||
size={20}
|
||||
className="text-icon-information"
|
||||
/>
|
||||
<span className="text-xs font-medium text-text-information flex-1 leading-[20px]">
|
||||
<span className="flex-1 text-xs font-medium leading-[20px] text-text-information">
|
||||
{t('layout.by-messaging-eigent')}{' '}
|
||||
<a
|
||||
href="https://www.eigent.ai/terms-of-use"
|
||||
|
|
@ -1138,7 +1131,7 @@ export default function ChatBox(): JSX.Element {
|
|||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="mr-2 gap-2 flex flex-col items-center">
|
||||
<div className="mr-2 flex flex-col items-center gap-2">
|
||||
{[
|
||||
{
|
||||
label: t('layout.it-ticket-creation'),
|
||||
|
|
@ -1155,7 +1148,7 @@ export default function ChatBox(): JSX.Element {
|
|||
].map(({ label, message }) => (
|
||||
<div
|
||||
key={label}
|
||||
className="rounded-md bg-surface-tertiary px-sm py-xs text-xs font-medium text-button-tertiery-text-default cursor-pointer leading-none opacity-70 transition-all duration-300 hover:opacity-100"
|
||||
className="cursor-pointer rounded-md bg-surface-tertiary px-sm py-xs text-xs font-medium leading-none text-button-tertiery-text-default opacity-70 transition-all duration-300 hover:opacity-100"
|
||||
onClick={() => {
|
||||
setMessage(message);
|
||||
}}
|
||||
|
|
|
|||
|
|
@ -59,19 +59,13 @@ export default function SettingPrivacy() {
|
|||
useEffect(() => {
|
||||
proxyFetchGet('/api/user/privacy')
|
||||
.then((res) => {
|
||||
let hasFalse = false;
|
||||
setSettings((prev) =>
|
||||
prev.map((item, index) => {
|
||||
if (!res[API_FIELDS[index]]) {
|
||||
hasFalse = true;
|
||||
}
|
||||
return {
|
||||
...item,
|
||||
checked: res[API_FIELDS[index]] || false,
|
||||
};
|
||||
})
|
||||
prev.map((item, index) => ({
|
||||
...item,
|
||||
checked: res[API_FIELDS[index]] || false,
|
||||
}))
|
||||
);
|
||||
setPrivacy(!hasFalse);
|
||||
setPrivacy(res.all_required_granted);
|
||||
})
|
||||
.catch((err) => console.error('Failed to fetch settings:', err));
|
||||
}, [API_FIELDS]);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue