@lobehub/lobehub 2.0.0-next.123 → 2.0.0-next.124

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.
@@ -336,7 +336,14 @@
336
336
  "when": 1763987922211,
337
337
  "tag": "0047_add_slug_document",
338
338
  "breakpoints": true
339
+ },
340
+ {
341
+ "idx": 48,
342
+ "version": "7",
343
+ "when": 1764215503726,
344
+ "tag": "0048_add_editor_data",
345
+ "breakpoints": true
339
346
  }
340
347
  ],
341
348
  "version": "6"
342
- }
349
+ }
@@ -797,5 +797,11 @@
797
797
  "bps": true,
798
798
  "folderMillis": 1763987922211,
799
799
  "hash": "f823b521f4d25e5dc5ab238b372727d2d2d7f0aed27b5eabc8a9608ce4e50568"
800
+ },
801
+ {
802
+ "sql": ["ALTER TABLE \"agents\" ADD COLUMN IF NOT EXISTS \"editor_data\" jsonb;"],
803
+ "bps": true,
804
+ "folderMillis": 1764215503726,
805
+ "hash": "4188893a9083b3c7baebdbad0dd3f9d9400ede7584ca2394f5c64305dc9ec7b0"
800
806
  }
801
807
  ]
@@ -34,6 +34,7 @@ export const agents = pgTable(
34
34
  title: varchar('title', { length: 255 }),
35
35
  description: varchar('description', { length: 1000 }),
36
36
  tags: jsonb('tags').$type<string[]>().default([]),
37
+ editorData: jsonb('editor_data'),
37
38
  avatar: text('avatar'),
38
39
  backgroundColor: text('background_color'),
39
40
  marketIdentifier: text('market_identifier'),
@@ -97,15 +97,15 @@ const TopicContent = memo<TopicContentProps>(({ id, title, fav, showMore }) => {
97
97
  },
98
98
  ...(isDesktop
99
99
  ? [
100
- {
101
- icon: <Icon icon={ExternalLink} />,
102
- key: 'openInNewWindow',
103
- label: t('actions.openInNewWindow'),
104
- onClick: () => {
105
- openTopicInNewWindow(activeId, id);
100
+ {
101
+ icon: <Icon icon={ExternalLink} />,
102
+ key: 'openInNewWindow',
103
+ label: t('actions.openInNewWindow'),
104
+ onClick: () => {
105
+ openTopicInNewWindow(activeId, id);
106
+ },
106
107
  },
107
- },
108
- ]
108
+ ]
109
109
  : []),
110
110
  {
111
111
  type: 'divider',
@@ -210,6 +210,13 @@ const TopicContent = memo<TopicContentProps>(({ id, title, fav, showMore }) => {
210
210
  ) : (
211
211
  <EditableText
212
212
  editing={editing}
213
+ onBlur={(e) => {
214
+ const v = (e.target as HTMLInputElement).value;
215
+ if (title !== v) {
216
+ updateTopicTitle(id, v);
217
+ }
218
+ toggleEditing(false);
219
+ }}
213
220
  onChangeEnd={(v) => {
214
221
  if (title !== v) {
215
222
  updateTopicTitle(id, v);
@@ -3,7 +3,6 @@ import { createStyles } from 'antd-style';
3
3
  import qs from 'query-string';
4
4
  import { Suspense, memo, useState } from 'react';
5
5
  import { Flexbox } from 'react-layout-kit';
6
- import { Link } from 'react-router-dom';
7
6
 
8
7
  import { useChatStore } from '@/store/chat';
9
8
  import { useGlobalStore } from '@/store/global';
@@ -54,47 +53,45 @@ export interface ConfigCellProps {
54
53
  const TopicItem = memo<ConfigCellProps>(({ title, active, id, fav, threadId }) => {
55
54
  const { styles, cx } = useStyles();
56
55
  const toggleConfig = useGlobalStore((s) => s.toggleMobileTopic);
57
- const [toggleTopic] = useChatStore((s) => [s.switchTopic]);
56
+ const [toggleTopic, editing] = useChatStore((s) => [s.switchTopic, s.topicRenamingId === id]);
58
57
  const activeId = useSessionStore((s) => s.activeId);
59
58
  const [isHover, setHovering] = useState(false);
60
59
 
61
- const topicUrl = qs.stringifyUrl({
62
- query: id ? { session: activeId, topic: id } : { session: activeId },
63
- url: '/chat',
64
- });
65
-
66
60
  return (
67
61
  <Flexbox style={{ position: 'relative' }}>
68
- <Link
62
+ <Flexbox
63
+ align={'center'}
64
+ className={cx(styles.container, 'topic-item', active && !threadId && styles.active)}
65
+ distribution={'space-between'}
66
+ horizontal
69
67
  onClick={(e) => {
70
- if (e.button === 0 && (e.metaKey || e.ctrlKey)) {
68
+ // 重命名时不切换话题
69
+ if (editing) return;
70
+ // Ctrl/Cmd+点击在新窗口打开
71
+ if (e.button === 0 && (e.metaKey || e.ctrlKey) && id) {
72
+ const topicUrl = qs.stringifyUrl({
73
+ query: { session: activeId, topic: id },
74
+ url: '/chat',
75
+ });
76
+ window.open(topicUrl, '_blank');
71
77
  return;
72
78
  }
73
- e.preventDefault();
74
79
  toggleTopic(id);
75
80
  toggleConfig(false);
76
81
  }}
77
- to={topicUrl}
82
+ onMouseEnter={() => {
83
+ setHovering(true);
84
+ }}
85
+ onMouseLeave={() => {
86
+ setHovering(false);
87
+ }}
78
88
  >
79
- <Flexbox
80
- align={'center'}
81
- className={cx(styles.container, 'topic-item', active && !threadId && styles.active)}
82
- distribution={'space-between'}
83
- horizontal
84
- onMouseEnter={() => {
85
- setHovering(true);
86
- }}
87
- onMouseLeave={() => {
88
- setHovering(false);
89
- }}
90
- >
91
- {!id ? (
92
- <DefaultContent />
93
- ) : (
94
- <TopicContent fav={fav} id={id} showMore={isHover} title={title} />
95
- )}
96
- </Flexbox>
97
- </Link>
89
+ {!id ? (
90
+ <DefaultContent />
91
+ ) : (
92
+ <TopicContent fav={fav} id={id} showMore={isHover} title={title} />
93
+ )}
94
+ </Flexbox>
98
95
  {active && (
99
96
  <Suspense
100
97
  fallback={
@@ -4,7 +4,7 @@ import { Avatar, Button, Form, type FormGroupItemType, Tag, Tooltip } from '@lob
4
4
  import { Empty, Space, Switch } from 'antd';
5
5
  import isEqual from 'fast-deep-equal';
6
6
  import { LucideTrash2, Store } from 'lucide-react';
7
- import Link from 'next/link';
7
+ import { Link, useNavigate } from 'react-router-dom';
8
8
  import { memo, useState } from 'react';
9
9
  import { Trans, useTranslation } from 'react-i18next';
10
10
  import { Center, Flexbox } from 'react-layout-kit';
@@ -29,6 +29,8 @@ const AgentPlugin = memo(() => {
29
29
 
30
30
  const [showStore, setShowStore] = useState(false);
31
31
 
32
+ const navigate = useNavigate();
33
+
32
34
  const [userEnabledPlugins, toggleAgentPlugin] = useStore((s) => [
33
35
  s.config.plugins || [],
34
36
  s.toggleAgentPlugin,
@@ -134,11 +136,13 @@ const AgentPlugin = memo(() => {
134
136
  <Trans i18nKey={'plugin.empty'} ns={'setting'}>
135
137
  暂无安装插件,
136
138
  <Link
137
- href={'/'}
138
139
  onClick={(e) => {
140
+ e.stopPropagation();
139
141
  e.preventDefault();
140
142
  setShowStore(true);
143
+ navigate('/discover/mcp');
141
144
  }}
145
+ to={'/discover/mcp'}
142
146
  >
143
147
  前往插件市场
144
148
  </Link>
@@ -9,14 +9,14 @@ import { createStoreUpdater } from 'zustand-utils';
9
9
  import { useIsMobile } from '@/hooks/useIsMobile';
10
10
  import { useAgentStore } from '@/store/agent';
11
11
  import { useAiInfraStore } from '@/store/aiInfra';
12
+ import { useElectronStore } from '@/store/electron';
13
+ import { electronSyncSelectors } from '@/store/electron/selectors';
12
14
  import { useGlobalStore } from '@/store/global';
13
15
  import { useServerConfigStore } from '@/store/serverConfig';
14
16
  import { serverConfigSelectors } from '@/store/serverConfig/selectors';
15
17
  import { useUrlHydrationStore } from '@/store/urlHydration';
16
18
  import { useUserStore } from '@/store/user';
17
19
  import { authSelectors } from '@/store/user/selectors';
18
- import { electronSyncSelectors } from '@/store/electron/selectors';
19
- import { useElectronStore } from '@/store/electron';
20
20
 
21
21
  const StoreInitialization = memo(() => {
22
22
  // prefetch error ns to avoid don't show error content correctly
@@ -68,7 +68,7 @@ const StoreInitialization = memo(() => {
68
68
  const isSyncActive = useElectronStore((s) => electronSyncSelectors.isSyncActive(s));
69
69
 
70
70
  // init user provider key vaults
71
- useInitAiProviderKeyVaults(isLoginOnInit,isSyncActive);
71
+ useInitAiProviderKeyVaults(isLoginOnInit, isSyncActive);
72
72
 
73
73
  // init user state
74
74
  useInitUserState(isLoginOnInit, serverConfig, {
@@ -77,10 +77,10 @@ export const normalizeImageModel = async (
77
77
  const fallbackParametersPromise = model.parameters
78
78
  ? Promise.resolve<ModelParamsSchema | undefined>(model.parameters)
79
79
  : getModelPropertyWithFallback<ModelParamsSchema | undefined>(
80
- model.id,
81
- 'parameters',
82
- model.providerId,
83
- );
80
+ model.id,
81
+ 'parameters',
82
+ model.providerId,
83
+ );
84
84
 
85
85
  const modelWithPricing = model as AIImageModelCard;
86
86
  const fallbackPricingPromise = modelWithPricing.pricing