@lobehub/chat 1.77.6 → 1.77.8
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/.github/scripts/pr-comment.js +80 -0
- package/.github/scripts/pr-release-body.js +59 -0
- package/.github/workflows/release-desktop.yml +331 -0
- package/.github/workflows/test.yml +1 -1
- package/CHANGELOG.md +58 -0
- package/changelog/v1.json +21 -0
- package/next.config.ts +16 -11
- package/package.json +92 -89
- package/packages/electron-client-ipc/README.md +48 -0
- package/packages/electron-client-ipc/package.json +7 -0
- package/packages/electron-client-ipc/src/events/devtools.ts +6 -0
- package/packages/electron-client-ipc/src/events/index.ts +13 -0
- package/packages/electron-client-ipc/src/index.ts +2 -0
- package/packages/electron-client-ipc/src/types/dispatch.ts +10 -0
- package/packages/electron-client-ipc/src/types/index.ts +1 -0
- package/packages/electron-server-ipc/README.md +1 -1
- package/packages/web-crawler/src/crawImpl/search1api.ts +20 -17
- package/pnpm-workspace.yaml +1 -0
- package/scripts/setup-test-postgres-db.sh +21 -0
- package/src/app/desktop/devtools/page.tsx +89 -0
- package/src/app/desktop/layout.tsx +31 -0
- package/src/app/layout.tsx +11 -0
- package/src/app/not-found.tsx +1 -0
- package/src/const/desktop.ts +1 -0
- package/src/const/version.ts +2 -0
- package/src/database/client/db.ts +3 -10
- package/src/database/models/__tests__/message.test.ts +97 -26
- package/src/database/models/__tests__/session.test.ts +2 -0
- package/src/database/models/drizzleMigration.ts +15 -0
- package/src/database/models/message.ts +10 -5
- package/src/database/models/user.ts +3 -0
- package/src/features/ChatInput/ActionBar/Token/TokenTag.tsx +13 -3
- package/src/features/DevPanel/features/FloatPanel.tsx +23 -6
- package/src/features/User/UserPanel/index.tsx +10 -6
- package/src/libs/trpc/middleware/userAuth.ts +10 -0
- package/src/server/routers/tools/__tests__/search.test.ts +1 -0
- package/src/server/translation.test.ts +72 -52
- package/src/server/translation.ts +2 -11
- package/src/services/electron/devtools.ts +9 -0
- package/src/styles/electron.ts +14 -0
- package/src/tools/web-browsing/Portal/Search/ResultList/SearchItem/index.tsx +3 -8
- package/src/tools/web-browsing/Render/Search/SearchResult/ShowMore.tsx +2 -4
- package/src/types/electron.ts +11 -0
- package/src/utils/electron/dispatch.ts +10 -0
- package/tsconfig.json +6 -6
- package/vitest.config.ts +3 -1
- package/vitest.server.config.ts +7 -3
@@ -0,0 +1,31 @@
|
|
1
|
+
import { notFound } from 'next/navigation';
|
2
|
+
import { NuqsAdapter } from 'nuqs/adapters/next/app';
|
3
|
+
import { ReactNode } from 'react';
|
4
|
+
|
5
|
+
import { isDesktop } from '@/const/version';
|
6
|
+
import GlobalLayout from '@/layout/GlobalProvider';
|
7
|
+
import { ServerConfigStoreProvider } from '@/store/serverConfig/Provider';
|
8
|
+
|
9
|
+
interface RootLayoutProps {
|
10
|
+
children: ReactNode;
|
11
|
+
}
|
12
|
+
|
13
|
+
const RootLayout = async ({ children }: RootLayoutProps) => {
|
14
|
+
if (!isDesktop) return notFound();
|
15
|
+
|
16
|
+
return (
|
17
|
+
<html dir="ltr" suppressHydrationWarning>
|
18
|
+
<body>
|
19
|
+
<NuqsAdapter>
|
20
|
+
<ServerConfigStoreProvider>
|
21
|
+
<GlobalLayout appearance={'auto'} isMobile={false} locale={''}>
|
22
|
+
{children}
|
23
|
+
</GlobalLayout>
|
24
|
+
</ServerConfigStoreProvider>
|
25
|
+
</NuqsAdapter>
|
26
|
+
</body>
|
27
|
+
</html>
|
28
|
+
);
|
29
|
+
};
|
30
|
+
|
31
|
+
export default RootLayout;
|
@@ -0,0 +1 @@
|
|
1
|
+
export { default } from '@/components/404';
|
@@ -0,0 +1 @@
|
|
1
|
+
export const DESKTOP_USER_ID = 'DEFAULT_DESKTOP_USER';
|
package/src/const/version.ts
CHANGED
@@ -7,6 +7,8 @@ export const CURRENT_VERSION = pkg.version;
|
|
7
7
|
export const isServerMode = process.env.NEXT_PUBLIC_SERVICE_MODE === 'server';
|
8
8
|
export const isUsePgliteDB = process.env.NEXT_PUBLIC_CLIENT_DB === 'pglite';
|
9
9
|
|
10
|
+
export const isDesktop = process.env.NEXT_PUBLIC_IS_DESKTOP_APP === '1';
|
11
|
+
|
10
12
|
export const isDeprecatedEdition = !isServerMode && !isUsePgliteDB;
|
11
13
|
|
12
14
|
// @ts-ignore
|
@@ -167,17 +167,10 @@ export class DatabaseManager {
|
|
167
167
|
// if hash is the same, no need to migrate
|
168
168
|
if (hash === cacheHash) {
|
169
169
|
try {
|
170
|
+
const drizzleMigration = new DrizzleMigrationModel(this.db as any);
|
171
|
+
|
170
172
|
// 检查数据库中是否存在表
|
171
|
-
|
172
|
-
const tablesResult = await this.db.execute(
|
173
|
-
sql`
|
174
|
-
SELECT COUNT(*) as table_count
|
175
|
-
FROM information_schema.tables
|
176
|
-
WHERE table_schema = 'public'
|
177
|
-
`,
|
178
|
-
);
|
179
|
-
|
180
|
-
const tableCount = parseInt((tablesResult.rows[0] as any).table_count || '0', 10);
|
173
|
+
const tableCount = await drizzleMigration.getTableCounts();
|
181
174
|
|
182
175
|
// 如果表数量大于0,则认为数据库已正确初始化
|
183
176
|
if (tableCount > 0) {
|
@@ -1660,7 +1660,15 @@ describe('MessageModel', () => {
|
|
1660
1660
|
|
1661
1661
|
describe('getHeatmaps', () => {
|
1662
1662
|
it('should return heatmap data for the last year', async () => {
|
1663
|
-
|
1663
|
+
// 使用固定日期进行测试
|
1664
|
+
vi.useFakeTimers();
|
1665
|
+
const fixedDate = new Date('2023-04-07T13:00:00Z');
|
1666
|
+
vi.setSystemTime(fixedDate);
|
1667
|
+
|
1668
|
+
const today = dayjs(fixedDate);
|
1669
|
+
const twoDaysAgoDate = today.subtract(2, 'day').format('YYYY-MM-DD');
|
1670
|
+
const oneDayAgoDate = today.subtract(1, 'day').format('YYYY-MM-DD');
|
1671
|
+
const todayDate = today.format('YYYY-MM-DD');
|
1664
1672
|
|
1665
1673
|
// 创建测试数据
|
1666
1674
|
await serverDB.insert(messages).values([
|
@@ -1695,31 +1703,39 @@ describe('MessageModel', () => {
|
|
1695
1703
|
expect(result.length).toBeLessThan(368);
|
1696
1704
|
|
1697
1705
|
// 检查两天前的数据
|
1698
|
-
const twoDaysAgo = result.find(
|
1699
|
-
(item) => item.date === today.subtract(2, 'day').format('YYYY-MM-DD'),
|
1700
|
-
);
|
1706
|
+
const twoDaysAgo = result.find((item) => item.date === twoDaysAgoDate);
|
1701
1707
|
expect(twoDaysAgo?.count).toBe(2);
|
1702
1708
|
expect(twoDaysAgo?.level).toBe(1);
|
1703
1709
|
|
1704
1710
|
// 检查一天前的数据
|
1705
|
-
const oneDayAgo = result.find(
|
1706
|
-
(item) => item.date === today.subtract(1, 'day').format('YYYY-MM-DD'),
|
1707
|
-
);
|
1711
|
+
const oneDayAgo = result.find((item) => item.date === oneDayAgoDate);
|
1708
1712
|
expect(oneDayAgo?.count).toBe(1);
|
1709
1713
|
expect(oneDayAgo?.level).toBe(1);
|
1710
1714
|
|
1711
1715
|
// 检查今天的数据
|
1712
|
-
const todayData = result.find((item) => item.date ===
|
1716
|
+
const todayData = result.find((item) => item.date === todayDate);
|
1713
1717
|
expect(todayData?.count).toBe(0);
|
1714
1718
|
expect(todayData?.level).toBe(0);
|
1719
|
+
|
1720
|
+
vi.useRealTimers();
|
1715
1721
|
});
|
1716
1722
|
|
1717
1723
|
it('should calculate correct levels based on message count', async () => {
|
1718
|
-
|
1724
|
+
// 使用固定日期进行测试
|
1725
|
+
vi.useFakeTimers();
|
1726
|
+
const fixedDate = new Date('2023-05-15T12:00:00Z');
|
1727
|
+
vi.setSystemTime(fixedDate);
|
1728
|
+
|
1729
|
+
const today = dayjs(fixedDate);
|
1730
|
+
const fourDaysAgoDate = today.subtract(4, 'day').format('YYYY-MM-DD');
|
1731
|
+
const threeDaysAgoDate = today.subtract(3, 'day').format('YYYY-MM-DD');
|
1732
|
+
const twoDaysAgoDate = today.subtract(2, 'day').format('YYYY-MM-DD');
|
1733
|
+
const oneDayAgoDate = today.subtract(1, 'day').format('YYYY-MM-DD');
|
1734
|
+
const todayDate = today.format('YYYY-MM-DD');
|
1719
1735
|
|
1720
1736
|
// 创建测试数据 - 不同数量的消息以测试不同的等级
|
1721
1737
|
await serverDB.insert(messages).values([
|
1722
|
-
// 1 message - level
|
1738
|
+
// 1 message - level 1
|
1723
1739
|
{
|
1724
1740
|
id: '1',
|
1725
1741
|
userId,
|
@@ -1727,7 +1743,7 @@ describe('MessageModel', () => {
|
|
1727
1743
|
content: 'message 1',
|
1728
1744
|
createdAt: today.subtract(4, 'day').toDate(),
|
1729
1745
|
},
|
1730
|
-
// 6 messages - level
|
1746
|
+
// 6 messages - level 2
|
1731
1747
|
...Array(6)
|
1732
1748
|
.fill(0)
|
1733
1749
|
.map((_, i) => ({
|
@@ -1737,7 +1753,7 @@ describe('MessageModel', () => {
|
|
1737
1753
|
content: `message 2-${i}`,
|
1738
1754
|
createdAt: today.subtract(3, 'day').toDate(),
|
1739
1755
|
})),
|
1740
|
-
// 11 messages - level
|
1756
|
+
// 11 messages - level 3
|
1741
1757
|
...Array(11)
|
1742
1758
|
.fill(0)
|
1743
1759
|
.map((_, i) => ({
|
@@ -1747,7 +1763,7 @@ describe('MessageModel', () => {
|
|
1747
1763
|
content: `message 3-${i}`,
|
1748
1764
|
createdAt: today.subtract(2, 'day').toDate(),
|
1749
1765
|
})),
|
1750
|
-
// 16 messages - level
|
1766
|
+
// 16 messages - level 4
|
1751
1767
|
...Array(16)
|
1752
1768
|
.fill(0)
|
1753
1769
|
.map((_, i) => ({
|
@@ -1773,33 +1789,88 @@ describe('MessageModel', () => {
|
|
1773
1789
|
const result = await messageModel.getHeatmaps();
|
1774
1790
|
|
1775
1791
|
// 检查不同天数的等级
|
1776
|
-
const fourDaysAgo = result.find(
|
1777
|
-
(item) => item.date === today.subtract(4, 'day').format('YYYY-MM-DD'),
|
1778
|
-
);
|
1792
|
+
const fourDaysAgo = result.find((item) => item.date === fourDaysAgoDate);
|
1779
1793
|
expect(fourDaysAgo?.count).toBe(1);
|
1780
1794
|
expect(fourDaysAgo?.level).toBe(1);
|
1781
1795
|
|
1782
|
-
const threeDaysAgo = result.find(
|
1783
|
-
(item) => item.date === today.subtract(3, 'day').format('YYYY-MM-DD'),
|
1784
|
-
);
|
1796
|
+
const threeDaysAgo = result.find((item) => item.date === threeDaysAgoDate);
|
1785
1797
|
expect(threeDaysAgo?.count).toBe(6);
|
1786
1798
|
expect(threeDaysAgo?.level).toBe(2);
|
1787
1799
|
|
1788
|
-
const twoDaysAgo = result.find(
|
1789
|
-
(item) => item.date === today.subtract(2, 'day').format('YYYY-MM-DD'),
|
1790
|
-
);
|
1800
|
+
const twoDaysAgo = result.find((item) => item.date === twoDaysAgoDate);
|
1791
1801
|
expect(twoDaysAgo?.count).toBe(11);
|
1792
1802
|
expect(twoDaysAgo?.level).toBe(3);
|
1793
1803
|
|
1794
|
-
const oneDayAgo = result.find(
|
1795
|
-
(item) => item.date === today.subtract(1, 'day').format('YYYY-MM-DD'),
|
1796
|
-
);
|
1804
|
+
const oneDayAgo = result.find((item) => item.date === oneDayAgoDate);
|
1797
1805
|
expect(oneDayAgo?.count).toBe(16);
|
1798
1806
|
expect(oneDayAgo?.level).toBe(4);
|
1799
1807
|
|
1800
|
-
const todayData = result.find((item) => item.date ===
|
1808
|
+
const todayData = result.find((item) => item.date === todayDate);
|
1801
1809
|
expect(todayData?.count).toBe(21);
|
1802
1810
|
expect(todayData?.level).toBe(4);
|
1811
|
+
|
1812
|
+
vi.useRealTimers();
|
1813
|
+
});
|
1814
|
+
|
1815
|
+
it.skip('should return time count correctly when 19:00 time', async () => {
|
1816
|
+
// 使用固定日期进行测试
|
1817
|
+
vi.useFakeTimers();
|
1818
|
+
const fixedDate = new Date('2025-04-02T19:00:00Z');
|
1819
|
+
vi.setSystemTime(fixedDate);
|
1820
|
+
|
1821
|
+
const today = dayjs(fixedDate);
|
1822
|
+
const twoDaysAgoDate = today.subtract(2, 'day').format('YYYY-MM-DD');
|
1823
|
+
const oneDayAgoDate = today.subtract(1, 'day').format('YYYY-MM-DD');
|
1824
|
+
const todayDate = today.format('YYYY-MM-DD');
|
1825
|
+
|
1826
|
+
// 创建测试数据
|
1827
|
+
await serverDB.insert(messages).values([
|
1828
|
+
{
|
1829
|
+
id: '1',
|
1830
|
+
userId,
|
1831
|
+
role: 'user',
|
1832
|
+
content: 'message 1',
|
1833
|
+
createdAt: today.subtract(2, 'day').toDate(),
|
1834
|
+
},
|
1835
|
+
{
|
1836
|
+
id: '2',
|
1837
|
+
userId,
|
1838
|
+
role: 'user',
|
1839
|
+
content: 'message 2',
|
1840
|
+
createdAt: today.subtract(2, 'day').toDate(),
|
1841
|
+
},
|
1842
|
+
{
|
1843
|
+
id: '3',
|
1844
|
+
userId,
|
1845
|
+
role: 'user',
|
1846
|
+
content: 'message 3',
|
1847
|
+
createdAt: today.subtract(1, 'day').toDate(),
|
1848
|
+
},
|
1849
|
+
]);
|
1850
|
+
|
1851
|
+
// 调用 getHeatmaps 方法
|
1852
|
+
const result = await messageModel.getHeatmaps();
|
1853
|
+
|
1854
|
+
// 断言结果
|
1855
|
+
expect(result.length).toBeGreaterThanOrEqual(366);
|
1856
|
+
expect(result.length).toBeLessThan(368);
|
1857
|
+
|
1858
|
+
// 检查两天前的数据
|
1859
|
+
const twoDaysAgo = result.find((item) => item.date === twoDaysAgoDate);
|
1860
|
+
expect(twoDaysAgo?.count).toBe(2);
|
1861
|
+
expect(twoDaysAgo?.level).toBe(1);
|
1862
|
+
|
1863
|
+
// 检查一天前的数据
|
1864
|
+
const oneDayAgo = result.find((item) => item.date === oneDayAgoDate);
|
1865
|
+
expect(oneDayAgo?.count).toBe(1);
|
1866
|
+
expect(oneDayAgo?.level).toBe(1);
|
1867
|
+
|
1868
|
+
// 检查今天的数据
|
1869
|
+
const todayData = result.find((item) => item.date === todayDate);
|
1870
|
+
expect(todayData?.count).toBe(0);
|
1871
|
+
expect(todayData?.level).toBe(0);
|
1872
|
+
|
1873
|
+
vi.useRealTimers();
|
1803
1874
|
});
|
1804
1875
|
|
1805
1876
|
it('should handle empty data', async () => {
|
@@ -894,7 +894,9 @@ describe('SessionModel', () => {
|
|
894
894
|
await trx.insert(topics).values([
|
895
895
|
{ id: 't1', sessionId: '1', userId },
|
896
896
|
{ id: 't2', sessionId: '1', userId },
|
897
|
+
{ id: 't6', sessionId: '1', userId },
|
897
898
|
{ id: 't3', sessionId: '2', userId },
|
899
|
+
{ id: 't8', sessionId: '2', userId },
|
898
900
|
{ id: 't4', sessionId: '3', userId },
|
899
901
|
]);
|
900
902
|
});
|
@@ -1,3 +1,5 @@
|
|
1
|
+
import { sql } from 'drizzle-orm';
|
2
|
+
|
1
3
|
import { LobeChatDatabase } from '@/database/type';
|
2
4
|
import { MigrationTableItem } from '@/types/clientDB';
|
3
5
|
|
@@ -8,6 +10,19 @@ export class DrizzleMigrationModel {
|
|
8
10
|
this.db = db;
|
9
11
|
}
|
10
12
|
|
13
|
+
getTableCounts = async () => {
|
14
|
+
// 这里使用 pg_tables 系统表查询用户表数量
|
15
|
+
const result = await this.db.execute(
|
16
|
+
sql`
|
17
|
+
SELECT COUNT(*) as table_count
|
18
|
+
FROM information_schema.tables
|
19
|
+
WHERE table_schema = 'public'
|
20
|
+
`,
|
21
|
+
);
|
22
|
+
|
23
|
+
return parseInt((result.rows[0] as any).table_count || '0');
|
24
|
+
};
|
25
|
+
|
11
26
|
getMigrationList = async () => {
|
12
27
|
const res = await this.db.execute(
|
13
28
|
'SELECT * FROM "drizzle"."__drizzle_migrations" ORDER BY "created_at" DESC;',
|
@@ -382,15 +382,20 @@ export class MessageModel {
|
|
382
382
|
.orderBy(desc(sql`heatmaps_date`));
|
383
383
|
|
384
384
|
const heatmapData: HeatmapsProps['data'] = [];
|
385
|
-
let currentDate = startDate;
|
385
|
+
let currentDate = startDate.clone();
|
386
|
+
|
387
|
+
const dateCountMap = new Map<string, number>();
|
388
|
+
for (const item of result) {
|
389
|
+
if (item?.date) {
|
390
|
+
const dateStr = dayjs(item.date as string).format('YYYY-MM-DD');
|
391
|
+
dateCountMap.set(dateStr, Number(item.count) || 0);
|
392
|
+
}
|
393
|
+
}
|
386
394
|
|
387
395
|
while (currentDate.isBefore(endDate) || currentDate.isSame(endDate, 'day')) {
|
388
396
|
const formattedDate = currentDate.format('YYYY-MM-DD');
|
389
|
-
const
|
390
|
-
(r) => r?.date && dayjs(r.date as string).format('YYYY-MM-DD') === formattedDate,
|
391
|
-
);
|
397
|
+
const count = dateCountMap.get(formattedDate) || 0;
|
392
398
|
|
393
|
-
const count = matchingResult ? matchingResult.count : 0;
|
394
399
|
const levelCount = count > 0 ? Math.ceil(count / 5) : 0;
|
395
400
|
const level = levelCount > 4 ? 4 : levelCount;
|
396
401
|
|
@@ -177,6 +177,9 @@ export class UserModel {
|
|
177
177
|
};
|
178
178
|
|
179
179
|
// Static method
|
180
|
+
static makeSureUserExist = async (db: LobeChatDatabase, userId: string) => {
|
181
|
+
await db.insert(users).values({ id: userId }).onConflictDoNothing();
|
182
|
+
};
|
180
183
|
|
181
184
|
static createUser = async (db: LobeChatDatabase, params: NewUser) => {
|
182
185
|
// if user already exists, skip creation
|
@@ -2,7 +2,7 @@ import { TokenTag, Tooltip } from '@lobehub/ui';
|
|
2
2
|
import { Popover } from 'antd';
|
3
3
|
import { useTheme } from 'antd-style';
|
4
4
|
import numeral from 'numeral';
|
5
|
-
import { memo } from 'react';
|
5
|
+
import { memo, useMemo } from 'react';
|
6
6
|
import { useTranslation } from 'react-i18next';
|
7
7
|
import { Center, Flexbox } from 'react-layout-kit';
|
8
8
|
|
@@ -12,7 +12,7 @@ import { useTokenCount } from '@/hooks/useTokenCount';
|
|
12
12
|
import { useAgentStore } from '@/store/agent';
|
13
13
|
import { agentChatConfigSelectors, agentSelectors } from '@/store/agent/selectors';
|
14
14
|
import { useChatStore } from '@/store/chat';
|
15
|
-
import { topicSelectors } from '@/store/chat/selectors';
|
15
|
+
import { chatSelectors, topicSelectors } from '@/store/chat/selectors';
|
16
16
|
import { useToolStore } from '@/store/tool';
|
17
17
|
import { toolSelectors } from '@/store/tool/selectors';
|
18
18
|
|
@@ -41,6 +41,11 @@ const Token = memo<TokenTagProps>(({ total: messageString }) => {
|
|
41
41
|
];
|
42
42
|
});
|
43
43
|
|
44
|
+
const [historyCount, enableHistoryCount] = useAgentStore((s) => [
|
45
|
+
agentChatConfigSelectors.historyCount(s),
|
46
|
+
agentChatConfigSelectors.enableHistoryCount(s),
|
47
|
+
]);
|
48
|
+
|
44
49
|
const maxTokens = useModelContextWindowTokens(model, provider);
|
45
50
|
|
46
51
|
// Tool usage token
|
@@ -60,7 +65,12 @@ const Token = memo<TokenTagProps>(({ total: messageString }) => {
|
|
60
65
|
// Chat usage token
|
61
66
|
const inputTokenCount = useTokenCount(input);
|
62
67
|
|
63
|
-
const
|
68
|
+
const chatsString = useMemo(() => {
|
69
|
+
const chats = chatSelectors.mainAIChatsWithHistoryConfig(useChatStore.getState());
|
70
|
+
return chats.map(chat => chat.content).join('');
|
71
|
+
}, [messageString, historyCount, enableHistoryCount]);
|
72
|
+
|
73
|
+
const chatsToken = useTokenCount(chatsString) + inputTokenCount;
|
64
74
|
|
65
75
|
// SystemRole token
|
66
76
|
const systemRoleToken = useTokenCount(systemRole);
|
@@ -4,14 +4,16 @@ import { ActionIcon, FluentEmoji, Icon, SideNav } from '@lobehub/ui';
|
|
4
4
|
import { FloatButton } from 'antd';
|
5
5
|
import { createStyles } from 'antd-style';
|
6
6
|
import { BugIcon, BugOff, XIcon } from 'lucide-react';
|
7
|
+
import { usePathname } from 'next/navigation';
|
7
8
|
import { ReactNode, memo, useEffect, useState } from 'react';
|
8
9
|
import { Flexbox } from 'react-layout-kit';
|
9
10
|
import { Rnd } from 'react-rnd';
|
10
11
|
|
11
12
|
import { BRANDING_NAME } from '@/const/branding';
|
13
|
+
import { isDesktop } from '@/const/version';
|
12
14
|
|
13
15
|
// 定义样式
|
14
|
-
const useStyles = createStyles(({ token, css, prefixCls }) => {
|
16
|
+
export const useStyles = createStyles(({ token, css, prefixCls }) => {
|
15
17
|
return {
|
16
18
|
collapsed: css`
|
17
19
|
pointer-events: none;
|
@@ -86,6 +88,7 @@ const CollapsibleFloatPanel = memo<CollapsibleFloatPanelProps>(({ items }) => {
|
|
86
88
|
const [position, setPosition] = useState({ x: 100, y: 100 });
|
87
89
|
const [size, setSize] = useState({ height: minHeight, width: minWidth });
|
88
90
|
|
91
|
+
const pathname = usePathname();
|
89
92
|
useEffect(() => {
|
90
93
|
try {
|
91
94
|
const localStoragePosition = localStorage.getItem('debug-panel-position');
|
@@ -108,11 +111,25 @@ const CollapsibleFloatPanel = memo<CollapsibleFloatPanelProps>(({ items }) => {
|
|
108
111
|
|
109
112
|
return (
|
110
113
|
<>
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
114
|
+
{
|
115
|
+
// desktop devtools 下隐藏
|
116
|
+
pathname !== '/desktop/devtools' && (
|
117
|
+
<FloatButton
|
118
|
+
className={styles.floatButton}
|
119
|
+
icon={<Icon icon={isExpanded ? BugOff : BugIcon} />}
|
120
|
+
onClick={async () => {
|
121
|
+
if (isDesktop) {
|
122
|
+
const { electronDevtoolsService } = await import('@/services/electron/devtools');
|
123
|
+
|
124
|
+
await electronDevtoolsService.openDevtools();
|
125
|
+
|
126
|
+
return;
|
127
|
+
}
|
128
|
+
setIsExpanded(!isExpanded);
|
129
|
+
}}
|
130
|
+
/>
|
131
|
+
)
|
132
|
+
}
|
116
133
|
{isExpanded && (
|
117
134
|
<Rnd
|
118
135
|
bounds="window"
|
@@ -4,16 +4,20 @@ import { Popover } from 'antd';
|
|
4
4
|
import { createStyles } from 'antd-style';
|
5
5
|
import { PropsWithChildren, memo, useState } from 'react';
|
6
6
|
|
7
|
+
import { isDesktop } from '@/const/version';
|
8
|
+
|
7
9
|
import PanelContent from './PanelContent';
|
8
10
|
import UpgradeBadge from './UpgradeBadge';
|
9
11
|
import { useNewVersion } from './useNewVersion';
|
10
12
|
|
11
|
-
const useStyles = createStyles(({ css }) =>
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
const useStyles = createStyles(({ css }) => {
|
14
|
+
return {
|
15
|
+
popover: css`
|
16
|
+
inset-block-start: ${isDesktop ? 24 : 8}px !important;
|
17
|
+
inset-inline-start: 8px !important;
|
18
|
+
`,
|
19
|
+
};
|
20
|
+
});
|
17
21
|
|
18
22
|
const UserPanel = memo<PropsWithChildren>(({ children }) => {
|
19
23
|
const hasNewVersion = useNewVersion();
|
@@ -1,11 +1,21 @@
|
|
1
1
|
import { TRPCError } from '@trpc/server';
|
2
2
|
|
3
3
|
import { enableClerk } from '@/const/auth';
|
4
|
+
import { DESKTOP_USER_ID } from '@/const/desktop';
|
5
|
+
import { isDesktop } from '@/const/version';
|
4
6
|
|
5
7
|
import { trpc } from '../init';
|
6
8
|
|
7
9
|
export const userAuth = trpc.middleware(async (opts) => {
|
8
10
|
const { ctx } = opts;
|
11
|
+
|
12
|
+
if (isDesktop) {
|
13
|
+
return opts.next({
|
14
|
+
ctx: {
|
15
|
+
userId: DESKTOP_USER_ID,
|
16
|
+
},
|
17
|
+
});
|
18
|
+
}
|
9
19
|
// `ctx.user` is nullable
|
10
20
|
if (!ctx.userId) {
|
11
21
|
if (enableClerk) {
|