@lobehub/lobehub 2.0.0-next.225 → 2.0.0-next.227
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +50 -0
- package/changelog/v1.json +18 -0
- package/docs/self-hosting/server-database/docker-compose.mdx +11 -0
- package/docs/self-hosting/server-database/docker-compose.zh-CN.mdx +11 -0
- package/locales/en-US/setting.json +4 -0
- package/locales/zh-CN/setting.json +4 -0
- package/package.json +2 -2
- package/packages/model-bank/src/aiModels/lobehub.ts +28 -0
- package/src/app/[variants]/(main)/chat/profile/features/Header/AgentPublishButton/ForkConfirmModal.tsx +67 -0
- package/src/app/[variants]/(main)/chat/profile/features/Header/AgentPublishButton/PublishButton.tsx +92 -105
- package/src/app/[variants]/(main)/chat/profile/features/Header/AgentPublishButton/index.tsx +13 -48
- package/src/app/[variants]/(main)/chat/profile/features/Header/AgentPublishButton/useMarketPublish.ts +69 -93
- package/src/business/client/hooks/useBusinessErrorAlertConfig.ts +9 -0
- package/src/business/client/hooks/useBusinessErrorContent.ts +13 -0
- package/src/business/server/lambda-routers/file.ts +12 -0
- package/src/features/Conversation/Error/index.tsx +13 -3
- package/src/layout/AuthProvider/MarketAuth/MarketAuthProvider.tsx +11 -28
- package/src/layout/AuthProvider/MarketAuth/ProfileSetupModal.tsx +30 -25
- package/src/layout/AuthProvider/MarketAuth/useMarketUserProfile.ts +4 -9
- package/src/libs/trpc/lambda/middleware/index.ts +1 -0
- package/src/libs/trpc/lambda/middleware/marketSDK.ts +68 -0
- package/src/locales/default/setting.ts +5 -0
- package/src/server/routers/lambda/__tests__/file.test.ts +7 -7
- package/src/server/routers/lambda/file.ts +12 -3
- package/src/server/routers/lambda/market/agent.ts +504 -0
- package/src/server/routers/lambda/market/index.ts +17 -0
- package/src/server/routers/lambda/market/oidc.ts +169 -0
- package/src/server/routers/lambda/market/social.ts +532 -0
- package/src/server/routers/lambda/market/user.ts +123 -0
- package/src/services/marketApi.ts +24 -84
- package/src/services/social.ts +70 -166
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [Version 2.0.0-next.227](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.226...v2.0.0-next.227)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2026-01-06**</sup>
|
|
8
|
+
|
|
9
|
+
#### 🐛 Bug Fixes
|
|
10
|
+
|
|
11
|
+
- **misc**: Allow zero-byte files and add business hooks for error handling.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's fixed
|
|
19
|
+
|
|
20
|
+
- **misc**: Allow zero-byte files and add business hooks for error handling, closes [#11283](https://github.com/lobehub/lobe-chat/issues/11283) ([38f5b78](https://github.com/lobehub/lobe-chat/commit/38f5b78))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
## [Version 2.0.0-next.226](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.225...v2.0.0-next.226)
|
|
31
|
+
|
|
32
|
+
<sup>Released on **2026-01-06**</sup>
|
|
33
|
+
|
|
34
|
+
#### ♻ Code Refactoring
|
|
35
|
+
|
|
36
|
+
- **misc**: Change all market routes & api call into lambda trpc client call.
|
|
37
|
+
|
|
38
|
+
<br/>
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
42
|
+
|
|
43
|
+
#### Code refactoring
|
|
44
|
+
|
|
45
|
+
- **misc**: Change all market routes & api call into lambda trpc client call, closes [#11256](https://github.com/lobehub/lobe-chat/issues/11256) ([8f7e378](https://github.com/lobehub/lobe-chat/commit/8f7e378))
|
|
46
|
+
|
|
47
|
+
</details>
|
|
48
|
+
|
|
49
|
+
<div align="right">
|
|
50
|
+
|
|
51
|
+
[](#readme-top)
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
5
55
|
## [Version 2.0.0-next.225](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.224...v2.0.0-next.225)
|
|
6
56
|
|
|
7
57
|
<sup>Released on **2026-01-06**</sup>
|
package/changelog/v1.json
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"children": {
|
|
4
|
+
"fixes": [
|
|
5
|
+
"Allow zero-byte files and add business hooks for error handling."
|
|
6
|
+
]
|
|
7
|
+
},
|
|
8
|
+
"date": "2026-01-06",
|
|
9
|
+
"version": "2.0.0-next.227"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"children": {
|
|
13
|
+
"improvements": [
|
|
14
|
+
"Change all market routes & api call into lambda trpc client call."
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
"date": "2026-01-06",
|
|
18
|
+
"version": "2.0.0-next.226"
|
|
19
|
+
},
|
|
2
20
|
{
|
|
3
21
|
"children": {},
|
|
4
22
|
"date": "2026-01-06",
|
|
@@ -440,6 +440,17 @@ Solutions:
|
|
|
440
440
|
|
|
441
441
|
- A straightforward troubleshooting method is to use the `curl` command in the LobeChat container terminal to access your authentication service at `https://auth.example.com/.well-known/openid-configuration`. If JSON format data is returned, it indicates your authentication service is functioning correctly.
|
|
442
442
|
|
|
443
|
+
#### OAuth Token Exchange Failures with Reverse Proxy
|
|
444
|
+
|
|
445
|
+
If OAuth authentication fails during the token exchange phase when using Docker behind a reverse proxy, this is typically caused by the default `MIDDLEWARE_REWRITE_THROUGH_LOCAL=1` setting which rewrites URLs to `127.0.0.1:3210`.
|
|
446
|
+
|
|
447
|
+
**Solution**: Set `MIDDLEWARE_REWRITE_THROUGH_LOCAL=0` in your `.env` file and restart Docker containers:
|
|
448
|
+
|
|
449
|
+
```bash
|
|
450
|
+
docker compose down
|
|
451
|
+
docker compose up -d
|
|
452
|
+
```
|
|
453
|
+
|
|
443
454
|
````markdown
|
|
444
455
|
## Extended Configuration
|
|
445
456
|
|
|
@@ -421,6 +421,17 @@ lobe-chat | [auth][error] TypeError: fetch failed
|
|
|
421
421
|
|
|
422
422
|
- 一个直接的排查方式,你可以在 LobeChat 容器的终端中,使用 `curl` 命令访问你的鉴权服务 `https://auth.example.com/.well-known/openid-configuration`,如果返回了 JSON 格式的数据,则说明你的鉴权服务正常运行。
|
|
423
423
|
|
|
424
|
+
#### 反向代理下 OAuth 令牌交换失败
|
|
425
|
+
|
|
426
|
+
如果在反向代理后使用 Docker 时 OAuth 认证在令牌交换阶段失败,这通常是由默认的 `MIDDLEWARE_REWRITE_THROUGH_LOCAL=1` 设置引起的,该设置会将 URL 重写为 `127.0.0.1:3210`。
|
|
427
|
+
|
|
428
|
+
**解决方案**: 在 `.env` 文件中设置 `MIDDLEWARE_REWRITE_THROUGH_LOCAL=0` 并重启 Docker 容器:
|
|
429
|
+
|
|
430
|
+
```bash
|
|
431
|
+
docker compose down
|
|
432
|
+
docker compose up -d
|
|
433
|
+
```
|
|
434
|
+
|
|
424
435
|
## 拓展配置
|
|
425
436
|
|
|
426
437
|
为了完善你的 LobeChat 服务,你可以根据你的需求进行以下拓展配置。
|
|
@@ -127,6 +127,10 @@
|
|
|
127
127
|
"llm.proxyUrl.title": "API proxy URL",
|
|
128
128
|
"llm.waitingForMore": "More models are <1>planned to be added</1>, stay tuned",
|
|
129
129
|
"llm.waitingForMoreLinkAriaLabel": "Open the Provider request form",
|
|
130
|
+
"marketPublish.forkConfirm.by": "by {{author}}",
|
|
131
|
+
"marketPublish.forkConfirm.confirm": "Confirm Publish",
|
|
132
|
+
"marketPublish.forkConfirm.description": "You are about to publish a derivative version based on an existing agent from the community. Your new agent will be created as a separate entry in the marketplace.",
|
|
133
|
+
"marketPublish.forkConfirm.title": "Publish Derivative Agent",
|
|
130
134
|
"marketPublish.modal.changelog.extra": "Describe the key changes and improvements in this version",
|
|
131
135
|
"marketPublish.modal.changelog.label": "Changelog",
|
|
132
136
|
"marketPublish.modal.changelog.maxLengthError": "Changelog must not exceed 500 characters",
|
|
@@ -127,6 +127,10 @@
|
|
|
127
127
|
"llm.proxyUrl.title": "API 代理地址",
|
|
128
128
|
"llm.waitingForMore": "更多模型正在 <1>计划接入</1> 中,敬请期待",
|
|
129
129
|
"llm.waitingForMoreLinkAriaLabel": "打开模型服务商接入需求表单",
|
|
130
|
+
"marketPublish.forkConfirm.by": "作者:{{author}}",
|
|
131
|
+
"marketPublish.forkConfirm.confirm": "确认发布",
|
|
132
|
+
"marketPublish.forkConfirm.description": "你即将基于社区中已存在的助理发布一个二次创作版本。你的新助理将作为独立条目发布到市场。",
|
|
133
|
+
"marketPublish.forkConfirm.title": "发布二次创作助理",
|
|
130
134
|
"marketPublish.modal.changelog.extra": "描述此版本的主要变更和改进",
|
|
131
135
|
"marketPublish.modal.changelog.label": "变更日志",
|
|
132
136
|
"marketPublish.modal.changelog.maxLengthError": "变更日志不能超过500个字符",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/lobehub",
|
|
3
|
-
"version": "2.0.0-next.
|
|
3
|
+
"version": "2.0.0-next.227",
|
|
4
4
|
"description": "LobeHub - an open-source,comprehensive AI Agent framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -204,7 +204,7 @@
|
|
|
204
204
|
"@lobehub/desktop-ipc-typings": "workspace:*",
|
|
205
205
|
"@lobehub/editor": "^3.4.1",
|
|
206
206
|
"@lobehub/icons": "^4.0.2",
|
|
207
|
-
"@lobehub/market-sdk": "^0.
|
|
207
|
+
"@lobehub/market-sdk": "^0.27.1",
|
|
208
208
|
"@lobehub/tts": "^4.0.2",
|
|
209
209
|
"@lobehub/ui": "^4.9.3",
|
|
210
210
|
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
@@ -860,6 +860,34 @@ const lobehubChatModels: AIChatModelCard[] = [
|
|
|
860
860
|
releasedAt: '2025-08-26',
|
|
861
861
|
type: 'chat',
|
|
862
862
|
},
|
|
863
|
+
{
|
|
864
|
+
abilities: {
|
|
865
|
+
functionCall: true,
|
|
866
|
+
reasoning: true,
|
|
867
|
+
search: true,
|
|
868
|
+
vision: true,
|
|
869
|
+
},
|
|
870
|
+
contextWindowTokens: 256_000,
|
|
871
|
+
description:
|
|
872
|
+
'Our newest and strongest flagship model, excelling in NLP, math, and reasoning—an ideal all-rounder.',
|
|
873
|
+
displayName: 'Grok 4',
|
|
874
|
+
enabled: true,
|
|
875
|
+
id: 'grok-4',
|
|
876
|
+
pricing: {
|
|
877
|
+
units: [
|
|
878
|
+
{ name: 'textInput_cacheRead', rate: 0.75, strategy: 'fixed', unit: 'millionTokens' },
|
|
879
|
+
{ name: 'textInput', rate: 3, strategy: 'fixed', unit: 'millionTokens' },
|
|
880
|
+
{ name: 'textOutput', rate: 15, strategy: 'fixed', unit: 'millionTokens' },
|
|
881
|
+
],
|
|
882
|
+
},
|
|
883
|
+
releasedAt: '2025-07-09',
|
|
884
|
+
settings: {
|
|
885
|
+
// reasoning_effort is not supported by grok-4. Specifying reasoning_effort parameter will get an error response.
|
|
886
|
+
// extendParams: ['reasoningEffort'],
|
|
887
|
+
searchImpl: 'params',
|
|
888
|
+
},
|
|
889
|
+
type: 'chat',
|
|
890
|
+
},
|
|
863
891
|
{
|
|
864
892
|
abilities: {
|
|
865
893
|
imageOutput: true,
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Avatar, Flexbox, Modal } from '@lobehub/ui';
|
|
4
|
+
import { memo } from 'react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
|
|
7
|
+
interface OriginalAgentInfo {
|
|
8
|
+
author?: {
|
|
9
|
+
avatar?: string;
|
|
10
|
+
name?: string;
|
|
11
|
+
userName?: string;
|
|
12
|
+
};
|
|
13
|
+
avatar?: string;
|
|
14
|
+
identifier: string;
|
|
15
|
+
name: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface ForkConfirmModalProps {
|
|
19
|
+
loading?: boolean;
|
|
20
|
+
onCancel: () => void;
|
|
21
|
+
onConfirm: () => void;
|
|
22
|
+
open: boolean;
|
|
23
|
+
originalAgent: OriginalAgentInfo | null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const ForkConfirmModal = memo<ForkConfirmModalProps>(
|
|
27
|
+
({ open, onCancel, onConfirm, originalAgent, loading }) => {
|
|
28
|
+
const { t } = useTranslation('setting');
|
|
29
|
+
|
|
30
|
+
if (!originalAgent) return null;
|
|
31
|
+
|
|
32
|
+
const authorName = originalAgent.author?.name || originalAgent.author?.userName || 'Unknown';
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<Modal
|
|
36
|
+
cancelText={t('cancel', { ns: 'common' })}
|
|
37
|
+
centered
|
|
38
|
+
closable
|
|
39
|
+
confirmLoading={loading}
|
|
40
|
+
okText={t('marketPublish.forkConfirm.confirm')}
|
|
41
|
+
onCancel={onCancel}
|
|
42
|
+
onOk={onConfirm}
|
|
43
|
+
open={open}
|
|
44
|
+
title={t('marketPublish.forkConfirm.title')}
|
|
45
|
+
width={480}
|
|
46
|
+
>
|
|
47
|
+
<Flexbox gap={16} style={{ marginTop: 16 }}>
|
|
48
|
+
<Flexbox align="center" gap={12} horizontal>
|
|
49
|
+
<Avatar avatar={originalAgent.avatar} size={48} style={{ flex: 'none' }} />
|
|
50
|
+
<Flexbox gap={4}>
|
|
51
|
+
<div style={{ fontWeight: 500 }}>{originalAgent.name}</div>
|
|
52
|
+
<div style={{ fontSize: 12, opacity: 0.6 }}>
|
|
53
|
+
{t('marketPublish.forkConfirm.by', { author: authorName })}
|
|
54
|
+
</div>
|
|
55
|
+
</Flexbox>
|
|
56
|
+
</Flexbox>
|
|
57
|
+
|
|
58
|
+
<p style={{ lineHeight: 1.6, margin: 0 }}>{t('marketPublish.forkConfirm.description')}</p>
|
|
59
|
+
</Flexbox>
|
|
60
|
+
</Modal>
|
|
61
|
+
);
|
|
62
|
+
},
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
ForkConfirmModal.displayName = 'ForkConfirmModal';
|
|
66
|
+
|
|
67
|
+
export default ForkConfirmModal;
|
package/src/app/[variants]/(main)/chat/profile/features/Header/AgentPublishButton/PublishButton.tsx
CHANGED
|
@@ -1,127 +1,107 @@
|
|
|
1
1
|
import { ActionIcon } from '@lobehub/ui';
|
|
2
2
|
import { ShapesUploadIcon } from '@lobehub/ui/icons';
|
|
3
|
-
import { memo, useCallback, useMemo } from 'react';
|
|
3
|
+
import { memo, useCallback, useMemo, useState } from 'react';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
|
|
6
6
|
import { message } from '@/components/AntdStaticMethods';
|
|
7
7
|
import { HEADER_ICON_SIZE } from '@/const/layoutTokens';
|
|
8
|
-
import { checkOwnership } from '@/hooks/useAgentOwnershipCheck';
|
|
9
8
|
import { useMarketAuth } from '@/layout/AuthProvider/MarketAuth';
|
|
10
9
|
import { resolveMarketAuthError } from '@/layout/AuthProvider/MarketAuth/errors';
|
|
11
10
|
import { useServerConfigStore } from '@/store/serverConfig';
|
|
12
11
|
|
|
12
|
+
import ForkConfirmModal from './ForkConfirmModal';
|
|
13
13
|
import type { MarketPublishAction } from './types';
|
|
14
|
-
import { useMarketPublish } from './useMarketPublish';
|
|
14
|
+
import { type OriginalAgentInfo, useMarketPublish } from './useMarketPublish';
|
|
15
15
|
|
|
16
16
|
interface MarketPublishButtonProps {
|
|
17
17
|
action: MarketPublishAction;
|
|
18
|
-
marketIdentifier?: string;
|
|
19
18
|
onPublishSuccess?: (identifier: string) => void;
|
|
20
19
|
}
|
|
21
20
|
|
|
22
|
-
const PublishButton = memo<MarketPublishButtonProps>(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
const buttonConfig = useMemo(() => {
|
|
35
|
-
if (action === 'upload') {
|
|
36
|
-
return {
|
|
37
|
-
authSuccessMessage: t('messages.success.upload', { ns: 'marketAuth' }),
|
|
38
|
-
authenticated: t('marketPublish.upload.tooltip'),
|
|
39
|
-
unauthenticated: t('marketPublish.upload.tooltip'),
|
|
40
|
-
} as const;
|
|
41
|
-
}
|
|
21
|
+
const PublishButton = memo<MarketPublishButtonProps>(({ action, onPublishSuccess }) => {
|
|
22
|
+
const { t } = useTranslation(['setting', 'marketAuth']);
|
|
23
|
+
|
|
24
|
+
const mobile = useServerConfigStore((s) => s.isMobile);
|
|
25
|
+
|
|
26
|
+
const { isAuthenticated, isLoading, signIn } = useMarketAuth();
|
|
27
|
+
const { checkOwnership, isCheckingOwnership, isPublishing, publish } = useMarketPublish({
|
|
28
|
+
action,
|
|
29
|
+
onSuccess: onPublishSuccess,
|
|
30
|
+
});
|
|
42
31
|
|
|
43
|
-
|
|
32
|
+
// Fork confirmation modal state
|
|
33
|
+
const [showForkModal, setShowForkModal] = useState(false);
|
|
34
|
+
const [originalAgentInfo, setOriginalAgentInfo] = useState<OriginalAgentInfo | null>(null);
|
|
44
35
|
|
|
36
|
+
const buttonConfig = useMemo(() => {
|
|
37
|
+
if (action === 'upload') {
|
|
45
38
|
return {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
unauthenticated: t('marketPublish.submit.tooltip'),
|
|
39
|
+
authenticated: t('marketPublish.upload.tooltip'),
|
|
40
|
+
unauthenticated: t('marketPublish.upload.tooltip'),
|
|
49
41
|
} as const;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
} catch (ownershipError) {
|
|
90
|
-
console.error('[MarketPublishButton] Failed to confirm ownership:', ownershipError);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// After authentication, proceed with publish
|
|
96
|
-
await publish();
|
|
97
|
-
} catch (error) {
|
|
98
|
-
console.error(`[MarketPublishButton][${action}] Authorization failed:`, error);
|
|
99
|
-
const normalizedError = resolveMarketAuthError(error);
|
|
100
|
-
message.error({
|
|
101
|
-
content: t(`errors.${normalizedError.code}`, { ns: 'marketAuth' }),
|
|
102
|
-
key: 'market-auth',
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const submitText = t('submitAgentModal.tooltips');
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
authenticated: submitText,
|
|
48
|
+
unauthenticated: t('marketPublish.submit.tooltip'),
|
|
49
|
+
} as const;
|
|
50
|
+
}, [action, t]);
|
|
51
|
+
|
|
52
|
+
const doPublish = useCallback(async () => {
|
|
53
|
+
// Check ownership before publishing
|
|
54
|
+
const { needsForkConfirm, originalAgent } = await checkOwnership();
|
|
55
|
+
|
|
56
|
+
if (needsForkConfirm && originalAgent) {
|
|
57
|
+
// Show fork confirmation modal
|
|
58
|
+
setOriginalAgentInfo(originalAgent);
|
|
59
|
+
setShowForkModal(true);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// No confirmation needed, proceed with publish
|
|
64
|
+
await publish();
|
|
65
|
+
}, [checkOwnership, publish]);
|
|
66
|
+
|
|
67
|
+
const handleButtonClick = useCallback(async () => {
|
|
68
|
+
if (!isAuthenticated) {
|
|
69
|
+
try {
|
|
70
|
+
await signIn();
|
|
71
|
+
// After authentication, proceed with ownership check and publish
|
|
72
|
+
await doPublish();
|
|
73
|
+
} catch (error) {
|
|
74
|
+
console.error(`[MarketPublishButton][${action}] Authorization failed:`, error);
|
|
75
|
+
const normalizedError = resolveMarketAuthError(error);
|
|
76
|
+
message.error({
|
|
77
|
+
content: t(`errors.${normalizedError.code}`, { ns: 'marketAuth' }),
|
|
78
|
+
key: 'market-auth',
|
|
79
|
+
});
|
|
106
80
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// User is authenticated, check ownership and publish
|
|
85
|
+
await doPublish();
|
|
86
|
+
}, [action, doPublish, isAuthenticated, signIn, t]);
|
|
87
|
+
|
|
88
|
+
const handleForkConfirm = useCallback(async () => {
|
|
89
|
+
setShowForkModal(false);
|
|
90
|
+
setOriginalAgentInfo(null);
|
|
91
|
+
// User confirmed, proceed with publish
|
|
92
|
+
await publish();
|
|
93
|
+
}, [publish]);
|
|
94
|
+
|
|
95
|
+
const handleForkCancel = useCallback(() => {
|
|
96
|
+
setShowForkModal(false);
|
|
97
|
+
setOriginalAgentInfo(null);
|
|
98
|
+
}, []);
|
|
99
|
+
|
|
100
|
+
const buttonTitle = isAuthenticated ? buttonConfig.authenticated : buttonConfig.unauthenticated;
|
|
101
|
+
const loading = isLoading || isCheckingOwnership || isPublishing;
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<>
|
|
125
105
|
<ActionIcon
|
|
126
106
|
icon={ShapesUploadIcon}
|
|
127
107
|
loading={loading}
|
|
@@ -129,9 +109,16 @@ const PublishButton = memo<MarketPublishButtonProps>(
|
|
|
129
109
|
size={HEADER_ICON_SIZE(mobile)}
|
|
130
110
|
title={buttonTitle}
|
|
131
111
|
/>
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
112
|
+
<ForkConfirmModal
|
|
113
|
+
loading={isPublishing}
|
|
114
|
+
onCancel={handleForkCancel}
|
|
115
|
+
onConfirm={handleForkConfirm}
|
|
116
|
+
open={showForkModal}
|
|
117
|
+
originalAgent={originalAgentInfo}
|
|
118
|
+
/>
|
|
119
|
+
</>
|
|
120
|
+
);
|
|
121
|
+
});
|
|
135
122
|
|
|
136
123
|
PublishButton.displayName = 'MarketPublishButton';
|
|
137
124
|
|
|
@@ -1,20 +1,22 @@
|
|
|
1
|
-
import { ActionIcon } from '@lobehub/ui';
|
|
2
1
|
import isEqual from 'fast-deep-equal';
|
|
3
|
-
import {
|
|
4
|
-
import { memo, useCallback, useMemo, useState } from 'react';
|
|
5
|
-
import { useTranslation } from 'react-i18next';
|
|
2
|
+
import { memo, useCallback, useState } from 'react';
|
|
6
3
|
|
|
7
|
-
import { useAgentOwnershipCheck } from '@/hooks/useAgentOwnershipCheck';
|
|
8
4
|
import { useAgentStore } from '@/store/agent';
|
|
9
5
|
import { agentSelectors } from '@/store/agent/selectors';
|
|
10
6
|
|
|
11
7
|
import PublishButton from './PublishButton';
|
|
12
8
|
import PublishResultModal from './PublishResultModal';
|
|
13
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Agent Publish Button Component
|
|
12
|
+
*
|
|
13
|
+
* Simplified version - backend now handles ownership check automatically.
|
|
14
|
+
* The action type (submit vs upload) is determined by backend based on:
|
|
15
|
+
* 1. Whether the identifier exists
|
|
16
|
+
* 2. Whether the current user is the owner
|
|
17
|
+
*/
|
|
14
18
|
const AgentPublishButton = memo(() => {
|
|
15
|
-
const { t } = useTranslation('setting');
|
|
16
19
|
const meta = useAgentStore(agentSelectors.currentAgentMeta, isEqual);
|
|
17
|
-
const { isOwnAgent } = useAgentOwnershipCheck(meta?.marketIdentifier);
|
|
18
20
|
|
|
19
21
|
const [showResultModal, setShowResultModal] = useState(false);
|
|
20
22
|
const [publishedIdentifier, setPublishedIdentifier] = useState<string>();
|
|
@@ -24,50 +26,13 @@ const AgentPublishButton = memo(() => {
|
|
|
24
26
|
setShowResultModal(true);
|
|
25
27
|
}, []);
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
if (isOwnAgent === null) {
|
|
32
|
-
return 'loading';
|
|
33
|
-
}
|
|
34
|
-
if (isOwnAgent === true) {
|
|
35
|
-
return 'upload';
|
|
36
|
-
}
|
|
37
|
-
return 'submit';
|
|
38
|
-
}, [meta?.marketIdentifier, isOwnAgent]);
|
|
39
|
-
|
|
40
|
-
const content = useMemo(() => {
|
|
41
|
-
switch (buttonType) {
|
|
42
|
-
case 'upload': {
|
|
43
|
-
return (
|
|
44
|
-
<PublishButton
|
|
45
|
-
action="upload"
|
|
46
|
-
marketIdentifier={meta?.marketIdentifier}
|
|
47
|
-
onPublishSuccess={handlePublishSuccess}
|
|
48
|
-
/>
|
|
49
|
-
);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
case 'submit': {
|
|
53
|
-
return (
|
|
54
|
-
<PublishButton
|
|
55
|
-
action="submit"
|
|
56
|
-
marketIdentifier={meta?.marketIdentifier}
|
|
57
|
-
onPublishSuccess={handlePublishSuccess}
|
|
58
|
-
/>
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
default: {
|
|
63
|
-
return <ActionIcon disabled icon={Loader2} loading title={t('checkingPermissions')} />;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}, [buttonType, meta?.marketIdentifier]);
|
|
29
|
+
// Determine action based on whether we have an existing marketIdentifier
|
|
30
|
+
// Backend will verify ownership and decide to create new or update
|
|
31
|
+
const action = meta?.marketIdentifier ? 'upload' : 'submit';
|
|
67
32
|
|
|
68
33
|
return (
|
|
69
34
|
<>
|
|
70
|
-
{
|
|
35
|
+
<PublishButton action={action} onPublishSuccess={handlePublishSuccess} />
|
|
71
36
|
<PublishResultModal
|
|
72
37
|
identifier={publishedIdentifier}
|
|
73
38
|
onCancel={() => setShowResultModal(false)}
|