Skip to content

Commit 1d97a68

Browse files
authored
💄 style: fix init state of loading (lobehub#7694)
1 parent 80558b2 commit 1d97a68

File tree

13 files changed

+170
-170
lines changed

13 files changed

+170
-170
lines changed

src/app/(backend)/webapi/assistant/[id]/route.ts

Lines changed: 0 additions & 25 deletions
This file was deleted.

src/app/(backend)/webapi/assistant/store/route.ts

Lines changed: 0 additions & 31 deletions
This file was deleted.

src/app/(backend)/webapi/plugin/store/route.ts

Lines changed: 0 additions & 43 deletions
This file was deleted.

src/features/ElectronTitlebar/index.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,22 @@ import { TITLE_BAR_HEIGHT } from './const';
1515
const isMac = isMacOS();
1616

1717
const TitleBar = memo(() => {
18-
const initElectronAppState = useElectronStore((s) => s.useInitElectronAppState);
18+
const [isAppStateInit, initElectronAppState] = useElectronStore((s) => [
19+
s.isAppStateInit,
20+
s.useInitElectronAppState,
21+
]);
1922

2023
initElectronAppState();
2124

25+
const showWinControl = isAppStateInit && !isMac;
2226
return (
2327
<Flexbox
2428
align={'center'}
2529
className={electronStylish.draggable}
2630
height={TITLE_BAR_HEIGHT}
2731
horizontal
2832
justify={'space-between'}
29-
paddingInline={isMac ? 12 : '12px 0'}
33+
paddingInline={showWinControl ? '12px 0' : 12}
3034
style={{ minHeight: TITLE_BAR_HEIGHT }}
3135
width={'100%'}
3236
>
@@ -38,7 +42,7 @@ const TitleBar = memo(() => {
3842
<UpdateNotification />
3943
<Connection />
4044
</Flexbox>
41-
{!isMac && (
45+
{showWinControl && (
4246
<>
4347
<Divider type={'vertical'} />
4448
<WinControl />

src/server/modules/AssistantStore/index.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ export class AssistantStore {
2626
return urlJoin(this.baseUrl, `${identifier}.${normalizeLocale(lang)}.json`);
2727
};
2828

29-
getAgentIndex = async (locale: Locales = DEFAULT_LANG, revalidate?: number) => {
29+
getAgentIndex = async (
30+
locale: Locales = DEFAULT_LANG,
31+
revalidate?: number,
32+
): Promise<AgentStoreIndex> => {
3033
try {
3134
let res: Response;
3235

@@ -42,7 +45,7 @@ export class AssistantStore {
4245

4346
if (!res.ok) {
4447
console.warn('fetch agent index error:', await res.text());
45-
return [];
48+
return { agents: [], schemaVersion: 1 };
4649
}
4750

4851
const data: AgentStoreIndex = await res.json();

src/server/routers/edge/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,14 @@ import { publicProcedure, router } from '@/libs/trpc/edge';
55

66
import { appStatusRouter } from './appStatus';
77
import { configRouter } from './config';
8+
import { marketRouter } from './market';
89
import { uploadRouter } from './upload';
910

1011
export const edgeRouter = router({
1112
appStatus: appStatusRouter,
1213
config: configRouter,
1314
healthcheck: publicProcedure.query(() => "i'm live!"),
15+
market: marketRouter,
1416
upload: uploadRouter,
1517
});
1618

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
import { TRPCError } from '@trpc/server';
2+
import { z } from 'zod';
3+
4+
import { DEFAULT_LANG } from '@/const/locale';
5+
import { publicProcedure, router } from '@/libs/trpc/edge';
6+
import { Locales } from '@/locales/resources';
7+
import { AssistantStore } from '@/server/modules/AssistantStore';
8+
import { PluginStore } from '@/server/modules/PluginStore';
9+
import { AgentStoreIndex } from '@/types/discover';
10+
11+
export const marketRouter = router({
12+
getAgent: publicProcedure
13+
.input(
14+
z.object({
15+
id: z.string(),
16+
locale: z.string().optional(),
17+
}),
18+
)
19+
.query(async ({ input }) => {
20+
const { id, locale } = input;
21+
22+
const market = new AssistantStore();
23+
24+
// 获取助手 URL
25+
const url = market.getAgentUrl(id, locale as Locales);
26+
27+
// 获取助手数据
28+
let res = await fetch(url);
29+
30+
// 如果找不到对应语言的助手,尝试获取默认语言的助手
31+
if (res.status === 404) {
32+
res = await fetch(market.getAgentUrl(id, DEFAULT_LANG));
33+
}
34+
35+
if (!res.ok) {
36+
throw new Error(`Failed to fetch agent with id ${id}`);
37+
}
38+
39+
return res.json();
40+
}),
41+
42+
getAgentIndex: publicProcedure
43+
.input(
44+
z
45+
.object({
46+
locale: z.string().optional(),
47+
})
48+
.optional(),
49+
)
50+
.query(async ({ input }): Promise<AgentStoreIndex> => {
51+
const locale = input?.locale;
52+
53+
const market = new AssistantStore();
54+
try {
55+
return await market.getAgentIndex(locale as Locales);
56+
} catch (e) {
57+
// it means failed to fetch
58+
if ((e as Error).message.includes('fetch failed')) {
59+
return { agents: [], schemaVersion: 1 };
60+
}
61+
62+
throw new TRPCError({
63+
code: 'INTERNAL_SERVER_ERROR',
64+
message: 'failed to fetch agent market index',
65+
});
66+
}
67+
}),
68+
69+
getPluginIndex: publicProcedure
70+
.input(
71+
z
72+
.object({
73+
locale: z.string().optional(),
74+
})
75+
.optional(),
76+
)
77+
.query(async ({ input }) => {
78+
const locale = input?.locale;
79+
80+
const pluginStore = new PluginStore();
81+
82+
try {
83+
// 获取插件索引URL
84+
let res = await fetch(pluginStore.getPluginIndexUrl(locale as Locales));
85+
86+
// 如果找不到对应语言的插件索引,尝试获取默认语言的插件索引
87+
if (res.status === 404) {
88+
res = await fetch(pluginStore.getPluginIndexUrl(DEFAULT_LANG));
89+
}
90+
91+
if (res.ok) {
92+
return res.json();
93+
}
94+
95+
throw new Error('Failed to fetch plugin index');
96+
} catch (e) {
97+
// it means failed to fetch
98+
if ((e as Error).message.includes('fetch failed')) {
99+
return [];
100+
}
101+
102+
throw new TRPCError({
103+
code: 'INTERNAL_SERVER_ERROR',
104+
message: 'failed to fetch plugin market index',
105+
});
106+
}
107+
}),
108+
});

src/services/__tests__/assistant.test.ts

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Mock, beforeEach, describe, expect, it, vi } from 'vitest';
22

3+
import { edgeClient } from '@/libs/trpc/client';
34
import { globalHelpers } from '@/store/global/helpers';
45

56
import { assistantService } from '../assistant';
@@ -12,6 +13,19 @@ vi.mock('@/store/global/helpers', () => ({
1213
},
1314
}));
1415

16+
vi.mock('@/libs/trpc/client', () => ({
17+
edgeClient: {
18+
market: {
19+
getAgentIndex: {
20+
query: vi.fn(),
21+
},
22+
getAgent: {
23+
query: vi.fn(),
24+
},
25+
},
26+
},
27+
}));
28+
1529
beforeEach(() => {
1630
vi.resetAllMocks();
1731
});
@@ -22,56 +36,49 @@ describe('AssistantService', () => {
2236
// Arrange
2337
const fakeResponse = { agents: [{ name: 'TestAssisstant' }] };
2438
(globalHelpers.getCurrentLanguage as Mock).mockReturnValue('tt');
25-
global.fetch = vi.fn(() =>
26-
Promise.resolve({
27-
json: () => Promise.resolve(fakeResponse),
28-
}),
29-
) as any;
39+
40+
(edgeClient.market.getAgentIndex.query as Mock).mockResolvedValue(fakeResponse);
3041

3142
// Act
3243
const assistantList = await assistantService.getAssistantList();
3344

3445
// Assert
3546
expect(globalHelpers.getCurrentLanguage).toHaveBeenCalled();
36-
expect(fetch).toHaveBeenCalledWith('/webapi/assistant/store?locale=tt');
3747
expect(assistantList).toEqual(fakeResponse.agents);
3848
});
3949

4050
it('should handle fetch error', async () => {
4151
// Arrange
42-
const fakeUrl = 'http://fake-url.com/plugins.json';
4352
(globalHelpers.getCurrentLanguage as Mock).mockReturnValue('en');
44-
global.fetch = vi.fn(() => Promise.reject(new Error('Network error')));
53+
(edgeClient.market.getAgentIndex.query as Mock).mockRejectedValue(
54+
new Error('Network error'),
55+
);
4556

4657
// Act & Assert
4758
await expect(assistantService.getAssistantList()).rejects.toThrow('Network error');
4859
});
4960
});
50-
describe('getAssistantList', () => {
51-
it('should fetch and return the assistant list', async () => {
61+
62+
describe('getAssistantById', () => {
63+
it('should fetch and return the assistant by id', async () => {
5264
// Arrange
5365
const fakeResponse = { identifier: 'test-assisstant' };
5466
(globalHelpers.getCurrentLanguage as Mock).mockReturnValue('tt');
55-
global.fetch = vi.fn(() =>
56-
Promise.resolve({
57-
json: () => Promise.resolve(fakeResponse),
58-
}),
59-
) as any;
67+
68+
(edgeClient.market.getAgent.query as Mock).mockResolvedValue(fakeResponse);
6069

6170
// Act
6271
const assistant = await assistantService.getAssistantById('test-assisstant');
6372

6473
// Assert
6574
expect(globalHelpers.getCurrentLanguage).toHaveBeenCalled();
66-
expect(fetch).toHaveBeenCalledWith('/webapi/assistant/test-assisstant?locale=tt');
6775
expect(assistant.identifier).toEqual(fakeResponse.identifier);
6876
});
6977

7078
it('should handle fetch error', async () => {
7179
// Arrange
72-
const fakeUrl = 'http://fake-url.com/plugins.json';
7380
(globalHelpers.getCurrentLanguage as Mock).mockReturnValue('en');
74-
global.fetch = vi.fn(() => Promise.reject(new Error('Network error')));
81+
(edgeClient.market.getAgent.query as Mock).mockRejectedValue(new Error('Network error'));
7582

7683
// Act & Assert
7784
await expect(assistantService.getAssistantById('test-assisstant')).rejects.toThrow(

0 commit comments

Comments
 (0)