@qlover/create-app 0.12.0 → 1.0.0
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 +4 -0
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/templates/next-app/next.config.ts +4 -3
- package/dist/templates/next-app/package.json +14 -11
- package/dist/templates/next-app/src/app/[locale]/login/LoginForm.tsx +2 -3
- package/dist/templates/next-app/src/base/cases/DialogErrorPlugin.ts +6 -4
- package/dist/templates/next-app/src/base/cases/RequestEncryptPlugin.ts +14 -10
- package/dist/templates/next-app/src/base/cases/StringEncryptor.ts +2 -2
- package/dist/templates/next-app/src/base/port/I18nServiceInterface.ts +1 -4
- package/dist/templates/next-app/src/base/services/I18nService.ts +6 -2
- package/dist/templates/next-app/src/base/services/adminApi/AdminApiRequester.ts +11 -7
- package/dist/templates/next-app/src/base/services/adminApi/AdminLocalesApi.ts +11 -10
- package/dist/templates/next-app/src/base/services/adminApi/AdminUserApi.ts +16 -12
- package/dist/templates/next-app/src/base/services/appApi/AppApiPlugin.ts +19 -19
- package/dist/templates/next-app/src/base/services/appApi/AppApiRequester.ts +26 -21
- package/dist/templates/next-app/src/base/services/appApi/AppUserApi.ts +15 -6
- package/dist/templates/next-app/src/base/services/appApi/AppUserApiBootstrap.ts +12 -14
- package/dist/templates/next-app/src/core/bootstraps/BootstrapServer.ts +34 -17
- package/dist/templates/next-app/src/server/NextApiServer.ts +10 -4
- package/dist/templates/next-app/src/server/PasswordEncrypt.ts +2 -2
- package/dist/templates/next-app/src/server/controllers/UserController.ts +2 -2
- package/dist/templates/next-app/src/server/port/ServerInterface.ts +2 -2
- package/dist/templates/next-app/src/server/services/AdminAuthPlugin.ts +6 -7
- package/dist/templates/next-app/src/server/services/UserService.ts +2 -2
- package/dist/templates/next-app/src/uikit/components/BootstrapsProvider.tsx +11 -47
- package/dist/templates/react-app/__tests__/__mocks__/MockDialogHandler.ts +3 -2
- package/dist/templates/react-app/__tests__/__mocks__/createMockGlobals.ts +6 -1
- package/dist/templates/react-app/__tests__/src/base/cases/I18nKeyErrorPlugin.test.ts +21 -61
- package/dist/templates/react-app/__tests__/src/base/cases/RequestLogger.test.ts +29 -51
- package/dist/templates/react-app/__tests__/src/core/bootstraps/BootstrapClient.test.ts +8 -26
- package/dist/templates/react-app/__tests__/src/main.test.tsx +2 -2
- package/dist/templates/react-app/config/IOCIdentifier.ts +1 -1
- package/dist/templates/react-app/docs/en/test-guide.md +5 -5
- package/dist/templates/react-app/docs/zh/test-guide.md +5 -5
- package/dist/templates/react-app/package.json +2 -1
- package/dist/templates/react-app/src/base/apis/AiApi.ts +20 -12
- package/dist/templates/react-app/src/base/apis/feApi/FeApi.ts +14 -5
- package/dist/templates/react-app/src/base/apis/feApi/FeApiBootstarp.ts +26 -13
- package/dist/templates/react-app/src/base/apis/userApi/UserApi.ts +30 -34
- package/dist/templates/react-app/src/base/apis/userApi/UserApiBootstarp.ts +20 -17
- package/dist/templates/react-app/src/base/cases/I18nKeyErrorPlugin.ts +11 -5
- package/dist/templates/react-app/src/base/cases/RequestLanguages.ts +19 -6
- package/dist/templates/react-app/src/base/cases/RequestLogger.ts +11 -11
- package/dist/templates/react-app/src/base/services/BaseLayoutService.ts +11 -5
- package/dist/templates/react-app/src/base/services/UserBootstrap.ts +6 -7
- package/dist/templates/react-app/src/base/services/UserService.ts +1 -5
- package/dist/templates/react-app/src/core/clientIoc/ClientIOCRegister.ts +6 -7
- package/dist/templates/react-app/src/main.tsx +1 -1
- package/dist/templates/react-app/src/pages/auth/LoginPage.tsx +5 -5
- package/dist/templates/react-app/src/pages/base/ExecutorPage.tsx +3 -1
- package/dist/templates/react-app/src/pages/base/JSONStoragePage.tsx +6 -2
- package/dist/templates/react-app/src/pages/base/MessagePage.tsx +34 -3
- package/dist/templates/react-app/src/uikit/bridges/ExecutorPageBridge.ts +13 -7
- package/dist/templates/react-app/src/uikit/components/LogoutButton.tsx +6 -1
- package/dist/templates/react-app/src/uikit/components/MessageBaseList.tsx +26 -11
- package/dist/templates/react-app/src/uikit/components/chatMessage/ChatMessageBridge.ts +1 -1
- package/dist/templates/react-app/src/uikit/components/chatMessage/FocusBar.tsx +3 -1
- package/dist/templates/react-app/src/uikit/components/chatMessage/MessageApi.ts +16 -7
- package/dist/templates/react-app/src/vite-env.d.ts +1 -1
- package/dist/templates/react-app/tsconfig.e2e.json +5 -2
- package/dist/templates/react-app/tsconfig.json +7 -0
- package/dist/templates/react-app/tsconfig.node.json +4 -2
- package/dist/templates/react-app/tsconfig.test.json +4 -1
- package/package.json +3 -3
- package/dist/templates/react-app/src/base/cases/AppError.ts +0 -10
- package/dist/templates/react-app/src/base/port/ProcesserExecutorInterface.ts +0 -20
- package/dist/templates/react-app/src/base/services/UserGatewayPlugin.ts +0 -20
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { IOCIdentifier } from '@config/IOCIdentifier';
|
|
2
2
|
import {
|
|
3
|
+
ExecutorContextInterface,
|
|
3
4
|
ExecutorError,
|
|
4
|
-
|
|
5
|
-
type ExecutorPlugin
|
|
5
|
+
LifecyclePluginInterface
|
|
6
6
|
} from '@qlover/fe-corekit';
|
|
7
7
|
import { inject, injectable } from 'inversify';
|
|
8
8
|
import type { I18nServiceInterface } from '../port/I18nServiceInterface';
|
|
@@ -14,7 +14,9 @@ import type { LoggerInterface } from '@qlover/logger';
|
|
|
14
14
|
* If the error thrown is an i18n key, it will be converted to the corresponding text
|
|
15
15
|
*/
|
|
16
16
|
@injectable()
|
|
17
|
-
export class I18nKeyErrorPlugin implements
|
|
17
|
+
export class I18nKeyErrorPlugin implements LifecyclePluginInterface<
|
|
18
|
+
ExecutorContextInterface<unknown, unknown>
|
|
19
|
+
> {
|
|
18
20
|
public readonly pluginName = 'I18nKeyErrorPlugin';
|
|
19
21
|
|
|
20
22
|
constructor(
|
|
@@ -30,7 +32,9 @@ export class I18nKeyErrorPlugin implements ExecutorPlugin {
|
|
|
30
32
|
/**
|
|
31
33
|
* @override
|
|
32
34
|
*/
|
|
33
|
-
public onError(
|
|
35
|
+
public onError(
|
|
36
|
+
context: ExecutorContextInterface<unknown, unknown>
|
|
37
|
+
): ExecutorError | void {
|
|
34
38
|
const { error } = context;
|
|
35
39
|
|
|
36
40
|
if (!error) {
|
|
@@ -39,6 +43,7 @@ export class I18nKeyErrorPlugin implements ExecutorPlugin {
|
|
|
39
43
|
|
|
40
44
|
if (error instanceof ExecutorError) {
|
|
41
45
|
const i18nText = this.translateById(error.id);
|
|
46
|
+
this.logger.error('i18nText', i18nText);
|
|
42
47
|
return new ExecutorError(error.id, i18nText);
|
|
43
48
|
}
|
|
44
49
|
|
|
@@ -50,7 +55,8 @@ export class I18nKeyErrorPlugin implements ExecutorPlugin {
|
|
|
50
55
|
|
|
51
56
|
if (i18nText && i18nText !== i18nKey) {
|
|
52
57
|
this.logger.debug('I18nKeyErrorPlugin Error:', i18nText);
|
|
53
|
-
|
|
58
|
+
// Use i18nText as cause (string) so ExecutorError.message will be the translated text
|
|
59
|
+
return new ExecutorError(i18nKey, i18nText);
|
|
54
60
|
}
|
|
55
61
|
}
|
|
56
62
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { I18nServiceInterface } from '@/base/port/I18nServiceInterface';
|
|
2
2
|
import type {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
ExecutorContextInterface,
|
|
4
|
+
LifecyclePluginInterface,
|
|
5
5
|
RequestAdapterConfig
|
|
6
6
|
} from '@qlover/fe-corekit';
|
|
7
7
|
|
|
8
|
-
export class RequestLanguages implements
|
|
8
|
+
export class RequestLanguages implements LifecyclePluginInterface<
|
|
9
|
+
ExecutorContextInterface<RequestAdapterConfig, unknown>
|
|
10
|
+
> {
|
|
9
11
|
public readonly pluginName = 'RequestLanguages';
|
|
10
12
|
|
|
11
13
|
constructor(
|
|
@@ -25,18 +27,29 @@ export class RequestLanguages implements ExecutorPlugin {
|
|
|
25
27
|
/**
|
|
26
28
|
* @override
|
|
27
29
|
*/
|
|
28
|
-
public onBefore(
|
|
30
|
+
public onBefore(
|
|
31
|
+
context: ExecutorContextInterface<RequestAdapterConfig, unknown>
|
|
32
|
+
): void {
|
|
29
33
|
const currentLanguage = this.i18nService.getCurrentLanguage();
|
|
30
34
|
const languages = this.i18nService.getSupportedLanguages();
|
|
31
35
|
|
|
32
36
|
if (!context.parameters.headers) {
|
|
33
|
-
context.
|
|
37
|
+
context.setParameters({
|
|
38
|
+
...context.parameters,
|
|
39
|
+
headers: {}
|
|
40
|
+
});
|
|
34
41
|
}
|
|
35
42
|
|
|
36
43
|
const languageValue = this.buildAcceptLanguage(
|
|
37
44
|
Array.from(new Set([currentLanguage, ...languages]))
|
|
38
45
|
);
|
|
39
46
|
|
|
40
|
-
context.
|
|
47
|
+
context.setParameters({
|
|
48
|
+
...context.parameters,
|
|
49
|
+
headers: {
|
|
50
|
+
...context.parameters.headers,
|
|
51
|
+
[this.headerName]: languageValue
|
|
52
|
+
}
|
|
53
|
+
});
|
|
41
54
|
}
|
|
42
55
|
}
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import { IOCIdentifier } from '@config/IOCIdentifier';
|
|
2
|
+
import { type ApiCatchPluginResponse } from '@qlover/corekit-bridge';
|
|
2
3
|
import {
|
|
3
|
-
type
|
|
4
|
-
type
|
|
5
|
-
} from '@qlover/corekit-bridge';
|
|
6
|
-
import {
|
|
7
|
-
type ExecutorPlugin,
|
|
8
|
-
type ExecutorContext,
|
|
4
|
+
type LifecyclePluginInterface,
|
|
5
|
+
type ExecutorContextInterface,
|
|
9
6
|
type RequestAdapterFetchConfig,
|
|
10
7
|
type RequestAdapterResponse
|
|
11
8
|
} from '@qlover/fe-corekit';
|
|
@@ -13,7 +10,9 @@ import { injectable, inject } from 'inversify';
|
|
|
13
10
|
import type { LoggerInterface } from '@qlover/logger';
|
|
14
11
|
|
|
15
12
|
@injectable()
|
|
16
|
-
export class RequestLogger implements
|
|
13
|
+
export class RequestLogger implements LifecyclePluginInterface<
|
|
14
|
+
ExecutorContextInterface<RequestAdapterFetchConfig, unknown>
|
|
15
|
+
> {
|
|
17
16
|
public readonly pluginName = 'RequestLogger';
|
|
18
17
|
|
|
19
18
|
constructor(@inject(IOCIdentifier.Logger) public logger: LoggerInterface) {}
|
|
@@ -22,7 +21,7 @@ export class RequestLogger implements ExecutorPlugin<RequestAdapterFetchConfig>
|
|
|
22
21
|
* @override
|
|
23
22
|
*/
|
|
24
23
|
public onBefore(
|
|
25
|
-
context:
|
|
24
|
+
context: ExecutorContextInterface<RequestAdapterFetchConfig, unknown>
|
|
26
25
|
): void {
|
|
27
26
|
this.logger.log(
|
|
28
27
|
`%c[Request before]%c [${new Date().toLocaleString()}] ${context.parameters.method} ${context.parameters.url}`,
|
|
@@ -38,8 +37,9 @@ export class RequestLogger implements ExecutorPlugin<RequestAdapterFetchConfig>
|
|
|
38
37
|
public async onSuccess({
|
|
39
38
|
parameters,
|
|
40
39
|
returnValue
|
|
41
|
-
}:
|
|
42
|
-
RequestAdapterFetchConfig
|
|
40
|
+
}: ExecutorContextInterface<
|
|
41
|
+
RequestAdapterFetchConfig,
|
|
42
|
+
unknown
|
|
43
43
|
>): Promise<void> {
|
|
44
44
|
const _returnValue = returnValue as RequestAdapterResponse &
|
|
45
45
|
ApiCatchPluginResponse;
|
|
@@ -65,7 +65,7 @@ export class RequestLogger implements ExecutorPlugin<RequestAdapterFetchConfig>
|
|
|
65
65
|
public onError({
|
|
66
66
|
parameters,
|
|
67
67
|
error
|
|
68
|
-
}:
|
|
68
|
+
}: ExecutorContextInterface<RequestAdapterFetchConfig, unknown>): void {
|
|
69
69
|
this.loggerError(parameters, error);
|
|
70
70
|
}
|
|
71
71
|
|
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
import { I } from '@config/IOCIdentifier';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
ExecutorContextInterface,
|
|
4
|
+
LifecycleExecutor,
|
|
5
|
+
LifecyclePluginInterface
|
|
6
|
+
} from '@qlover/fe-corekit';
|
|
3
7
|
import { injectable, inject } from 'inversify';
|
|
4
8
|
import { UserBootstrap } from './UserBootstrap';
|
|
5
9
|
import type { RouteServiceInterface } from '../port/RouteServiceInterface';
|
|
6
10
|
import type { UserServiceInterface } from '../port/UserServiceInterface';
|
|
7
11
|
import type {
|
|
8
|
-
|
|
12
|
+
BootstrapPluginOptions,
|
|
9
13
|
IOCContainerInterface
|
|
10
14
|
} from '@qlover/corekit-bridge';
|
|
11
15
|
import type { LoggerInterface } from '@qlover/logger';
|
|
12
16
|
|
|
13
17
|
@injectable()
|
|
14
18
|
export class BaseLayoutService {
|
|
15
|
-
protected executor:
|
|
19
|
+
protected executor: LifecycleExecutor = new LifecycleExecutor();
|
|
16
20
|
|
|
17
21
|
constructor(
|
|
18
22
|
@inject(I.Logger) protected logger: LoggerInterface,
|
|
@@ -24,7 +28,9 @@ export class BaseLayoutService {
|
|
|
24
28
|
this.use(new UserBootstrap(userService));
|
|
25
29
|
}
|
|
26
30
|
|
|
27
|
-
public use(
|
|
31
|
+
public use(
|
|
32
|
+
plugin: LifecyclePluginInterface<ExecutorContextInterface<unknown, unknown>>
|
|
33
|
+
): this {
|
|
28
34
|
this.executor.use(plugin);
|
|
29
35
|
return this;
|
|
30
36
|
}
|
|
@@ -36,7 +42,7 @@ export class BaseLayoutService {
|
|
|
36
42
|
}
|
|
37
43
|
|
|
38
44
|
public async starup(ioc: IOCContainerInterface): Promise<unknown> {
|
|
39
|
-
const context:
|
|
45
|
+
const context: BootstrapPluginOptions = {
|
|
40
46
|
root: {},
|
|
41
47
|
logger: this.logger,
|
|
42
48
|
ioc: ioc
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { LOCAL_NO_USER_TOKEN } from '@config/Identifier';
|
|
2
2
|
import { I } from '@config/IOCIdentifier';
|
|
3
|
+
import { ExecutorError } from '@qlover/fe-corekit';
|
|
3
4
|
import { inject, injectable } from 'inversify';
|
|
4
|
-
import { AppError } from '../cases/AppError';
|
|
5
5
|
import type { UserServiceInterface } from '../port/UserServiceInterface';
|
|
6
6
|
import type { BootstrapExecutorPlugin } from '@qlover/corekit-bridge';
|
|
7
7
|
|
|
@@ -17,7 +17,7 @@ export class UserBootstrap implements BootstrapExecutorPlugin {
|
|
|
17
17
|
/**
|
|
18
18
|
* @override
|
|
19
19
|
*/
|
|
20
|
-
public
|
|
20
|
+
public onBefore(): void {
|
|
21
21
|
const userService = this.userService;
|
|
22
22
|
|
|
23
23
|
if (userService.isAuthenticated()) {
|
|
@@ -29,18 +29,17 @@ export class UserBootstrap implements BootstrapExecutorPlugin {
|
|
|
29
29
|
if (userService.isUserCredential(credential)) {
|
|
30
30
|
userService.getStore().start();
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
userService.refreshUserInfo().then((user) => {
|
|
33
|
+
userService.getStore().success(user);
|
|
34
|
+
});
|
|
35
35
|
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
const newError = new
|
|
39
|
+
const newError = new ExecutorError(LOCAL_NO_USER_TOKEN);
|
|
40
40
|
|
|
41
41
|
userService.getStore().failed(newError);
|
|
42
42
|
|
|
43
|
-
// 否则还是抛出错误
|
|
44
43
|
throw newError;
|
|
45
44
|
}
|
|
46
45
|
}
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { I } from '@config/IOCIdentifier';
|
|
2
|
-
import {
|
|
3
|
-
UserService as CorekitBridgeUserService,
|
|
4
|
-
GatewayExecutor
|
|
5
|
-
} from '@qlover/corekit-bridge';
|
|
2
|
+
import { UserService as CorekitBridgeUserService } from '@qlover/corekit-bridge';
|
|
6
3
|
import { inject, injectable } from 'inversify';
|
|
7
4
|
import { isObject, isString } from 'lodash';
|
|
8
5
|
import { UserApi } from '@/base/apis/userApi/UserApi';
|
|
@@ -28,7 +25,6 @@ export class UserService
|
|
|
28
25
|
logger: LoggerInterface
|
|
29
26
|
) {
|
|
30
27
|
super({
|
|
31
|
-
executor: new GatewayExecutor(),
|
|
32
28
|
gateway: userApi,
|
|
33
29
|
logger: logger,
|
|
34
30
|
store: {
|
|
@@ -6,16 +6,15 @@ import { themeConfig } from '@config/theme';
|
|
|
6
6
|
import {
|
|
7
7
|
ApiCatchPlugin,
|
|
8
8
|
ApiMockPlugin,
|
|
9
|
-
RequestCommonPlugin,
|
|
10
9
|
ThemeService
|
|
11
10
|
} from '@qlover/corekit-bridge';
|
|
11
|
+
import { RequestPlugin } from '@qlover/fe-corekit';
|
|
12
12
|
import { I18nKeyErrorPlugin } from '@/base/cases/I18nKeyErrorPlugin';
|
|
13
13
|
import { RequestStatusCatcher } from '@/base/cases/RequestStatusCatcher';
|
|
14
14
|
import type { IocRegisterOptions } from '@/base/port/IOCInterface';
|
|
15
15
|
import type { UserServiceInterface } from '@/base/port/UserServiceInterface';
|
|
16
16
|
import { I18nService } from '@/base/services/I18nService';
|
|
17
17
|
import { RouteService } from '@/base/services/RouteService';
|
|
18
|
-
import { UserGatewayPlugin } from '@/base/services/UserGatewayPlugin';
|
|
19
18
|
import { UserService } from '@/base/services/UserService';
|
|
20
19
|
import { ExecutorPageBridge } from '@/uikit/bridges/ExecutorPageBridge';
|
|
21
20
|
import { JSONStoragePageBridge } from '@/uikit/bridges/JSONStoragePageBridge';
|
|
@@ -95,9 +94,10 @@ export class ClientIOCRegister implements IOCRegisterInterface<
|
|
|
95
94
|
|
|
96
95
|
ioc.bind(
|
|
97
96
|
I.UserServiceInterface,
|
|
98
|
-
ioc
|
|
99
|
-
|
|
100
|
-
|
|
97
|
+
ioc.get<UserService>(UserService)
|
|
98
|
+
// TODO: use executor replace
|
|
99
|
+
// .use(new UserGatewayPlugin(routeService))
|
|
100
|
+
// .use(ioc.get(I.I18nKeyErrorPlugin))
|
|
101
101
|
);
|
|
102
102
|
ioc.bind(I.RequestCatcherInterface, ioc.get(RequestStatusCatcher));
|
|
103
103
|
ioc.bind(I.ExecutorPageBridgeInterface, ioc.get(ExecutorPageBridge));
|
|
@@ -109,9 +109,8 @@ export class ClientIOCRegister implements IOCRegisterInterface<
|
|
|
109
109
|
const { appConfig } = this.options;
|
|
110
110
|
const logger = ioc.get<LoggerInterface>(I.Logger);
|
|
111
111
|
|
|
112
|
-
const feApiRequestCommonPlugin = new
|
|
112
|
+
const feApiRequestCommonPlugin = new RequestPlugin({
|
|
113
113
|
tokenPrefix: appConfig.openAiTokenPrefix,
|
|
114
|
-
requiredToken: true,
|
|
115
114
|
token: () =>
|
|
116
115
|
ioc.get<UserServiceInterface>(I.UserServiceInterface).getToken()
|
|
117
116
|
});
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import 'reflect-metadata';
|
|
3
3
|
import { StrictMode } from 'react';
|
|
4
4
|
import { createRoot } from 'react-dom/client';
|
|
5
|
-
import App from './App
|
|
5
|
+
import App from './App';
|
|
6
6
|
import { BootstrapClient } from './core/bootstraps/BootstrapClient';
|
|
7
7
|
import { clientIOC } from './core/clientIoc/ClientIOC';
|
|
8
8
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { UserOutlined, LockOutlined, GoogleOutlined } from '@ant-design/icons';
|
|
2
2
|
import { login18n } from '@config/i18n/login18n';
|
|
3
|
-
import {
|
|
3
|
+
import { I } from '@config/IOCIdentifier';
|
|
4
4
|
import { Form, Input, Button } from 'antd';
|
|
5
5
|
import { useState } from 'react';
|
|
6
6
|
import { LocaleLink } from '@/uikit/components/LocaleLink';
|
|
@@ -14,10 +14,10 @@ interface LoginFormData {
|
|
|
14
14
|
|
|
15
15
|
export default function LoginPage() {
|
|
16
16
|
const tt = useI18nInterface(login18n);
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
17
|
+
const logger = useIOC(I.Logger);
|
|
18
|
+
const userService = useIOC(I.UserServiceInterface);
|
|
19
|
+
const AppConfig = useIOC(I.AppConfig);
|
|
20
|
+
const routeService = useIOC(I.RouteServiceInterface);
|
|
21
21
|
|
|
22
22
|
const [loading, setLoading] = useState(false);
|
|
23
23
|
|
|
@@ -277,7 +277,9 @@ export default function ExecutorPage() {
|
|
|
277
277
|
<Input
|
|
278
278
|
placeholder={tt.enterUrl}
|
|
279
279
|
value={customUrl}
|
|
280
|
-
onChange={(e) =>
|
|
280
|
+
onChange={(e) =>
|
|
281
|
+
setCustomUrl((e.target as HTMLInputElement).value)
|
|
282
|
+
}
|
|
281
283
|
className="flex-1"
|
|
282
284
|
/>
|
|
283
285
|
<Select
|
|
@@ -74,7 +74,9 @@ export default function JSONStoragePage() {
|
|
|
74
74
|
type="number"
|
|
75
75
|
value={pageState.expireTime}
|
|
76
76
|
onChange={(e) =>
|
|
77
|
-
pageBridge.changeExpireTime(
|
|
77
|
+
pageBridge.changeExpireTime(
|
|
78
|
+
Number((e.target as HTMLInputElement).value)
|
|
79
|
+
)
|
|
78
80
|
}
|
|
79
81
|
className="w-32"
|
|
80
82
|
min="1000"
|
|
@@ -111,7 +113,9 @@ export default function JSONStoragePage() {
|
|
|
111
113
|
type="number"
|
|
112
114
|
value={pageState.requestTimeout}
|
|
113
115
|
onChange={(e) =>
|
|
114
|
-
pageBridge.changeRequestTimeout(
|
|
116
|
+
pageBridge.changeRequestTimeout(
|
|
117
|
+
Number((e.target as HTMLInputElement).value)
|
|
118
|
+
)
|
|
115
119
|
}
|
|
116
120
|
className="w-32"
|
|
117
121
|
min="1000"
|
|
@@ -3,8 +3,10 @@ import { chatMessageI18n } from '@config/i18n/chatMessageI18n';
|
|
|
3
3
|
import {
|
|
4
4
|
ChatMessageStore,
|
|
5
5
|
ChatSenderStrategy,
|
|
6
|
+
MessageSenderExecutor,
|
|
6
7
|
SendFailureStrategy
|
|
7
8
|
} from '@qlover/corekit-bridge';
|
|
9
|
+
import { Aborter, AborterPlugin } from '@qlover/fe-corekit';
|
|
8
10
|
import { useState } from 'react';
|
|
9
11
|
import { logger } from '@/core/globals';
|
|
10
12
|
import { ChatMessageBridge } from '@/uikit/components/chatMessage/ChatMessageBridge';
|
|
@@ -12,19 +14,48 @@ import { ChatRoot } from '@/uikit/components/chatMessage/ChatRoot';
|
|
|
12
14
|
import { MessageApi } from '@/uikit/components/chatMessage/MessageApi';
|
|
13
15
|
import { MessageBaseList } from '@/uikit/components/MessageBaseList';
|
|
14
16
|
import { useI18nInterface } from '@/uikit/hooks/useI18nInterface';
|
|
17
|
+
import { useIOC } from '@/uikit/hooks/useIOC';
|
|
18
|
+
import type { ChatMessage, MessageSenderOptions } from '@qlover/corekit-bridge';
|
|
19
|
+
import type { AborterConfig } from '@qlover/fe-corekit';
|
|
20
|
+
|
|
21
|
+
// TODO: message sender getconfig type not match, need to fix
|
|
22
|
+
function toAborterConfig<T>(
|
|
23
|
+
parameters: unknown | MessageSenderOptions<ChatMessage<T>>
|
|
24
|
+
): any {
|
|
25
|
+
const options = parameters as MessageSenderOptions<ChatMessage<T>>;
|
|
26
|
+
return {
|
|
27
|
+
abortId: options.currentMessage.id,
|
|
28
|
+
onAborted: options.gatewayOptions?.onAborted,
|
|
29
|
+
abortTimeout: options.gatewayOptions?.timeout,
|
|
30
|
+
signal: options.gatewayOptions?.signal
|
|
31
|
+
} as AborterConfig;
|
|
32
|
+
}
|
|
15
33
|
|
|
16
34
|
export default function MessagePage() {
|
|
17
35
|
const tt = useI18nInterface(chatMessageI18n);
|
|
18
36
|
const messagesStore = useFactory(ChatMessageStore<string>);
|
|
19
37
|
const messageApi = useFactory(MessageApi, messagesStore);
|
|
38
|
+
const aborter = useIOC(Aborter);
|
|
20
39
|
|
|
21
40
|
const [bridge] = useState(() => {
|
|
22
|
-
|
|
41
|
+
const messageBridge = new ChatMessageBridge<string>(messagesStore, {
|
|
23
42
|
gateway: messageApi,
|
|
24
43
|
logger: logger,
|
|
44
|
+
aborter: aborter,
|
|
25
45
|
senderName: 'ChatSender',
|
|
26
|
-
gatewayOptions: { stream: true }
|
|
27
|
-
|
|
46
|
+
gatewayOptions: { stream: true },
|
|
47
|
+
executor: new MessageSenderExecutor()
|
|
48
|
+
});
|
|
49
|
+
return messageBridge
|
|
50
|
+
.use(
|
|
51
|
+
new AborterPlugin<
|
|
52
|
+
AborterConfig & MessageSenderOptions<ChatMessage<string>>
|
|
53
|
+
>({
|
|
54
|
+
aborter: aborter,
|
|
55
|
+
getConfig: toAborterConfig
|
|
56
|
+
})
|
|
57
|
+
)
|
|
58
|
+
.use(new ChatSenderStrategy(SendFailureStrategy.KEEP_FAILED, logger));
|
|
28
59
|
});
|
|
29
60
|
|
|
30
61
|
return (
|
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
import { RequestState } from '@qlover/corekit-bridge';
|
|
2
|
-
import {
|
|
3
|
-
ExecutorPlugin,
|
|
4
|
-
RequestAdapterResponse,
|
|
5
|
-
RequestAdapterFetchConfig
|
|
6
|
-
} from '@qlover/fe-corekit';
|
|
7
2
|
import { inject, injectable } from 'inversify';
|
|
8
3
|
import cloneDeep from 'lodash/cloneDeep';
|
|
9
4
|
import { FeApi } from '@/base/apis/feApi/FeApi';
|
|
@@ -11,12 +6,20 @@ import {
|
|
|
11
6
|
ExecutorPageBridgeInterface,
|
|
12
7
|
ExecutorPageStateInterface
|
|
13
8
|
} from '@/base/port/ExecutorPageBridgeInterface';
|
|
9
|
+
import type {
|
|
10
|
+
RequestAdapterResponse,
|
|
11
|
+
RequestAdapterFetchConfig,
|
|
12
|
+
LifecyclePluginInterface,
|
|
13
|
+
ExecutorContextInterface
|
|
14
|
+
} from '@qlover/fe-corekit';
|
|
14
15
|
|
|
15
16
|
class ExecutorPageBridgeState implements ExecutorPageStateInterface {
|
|
16
17
|
public helloState = new RequestState();
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
const TestPlugin:
|
|
20
|
+
const TestPlugin: LifecyclePluginInterface<
|
|
21
|
+
ExecutorContextInterface<RequestAdapterFetchConfig, unknown>
|
|
22
|
+
> = {
|
|
20
23
|
pluginName: 'test',
|
|
21
24
|
async onSuccess({ parameters, returnValue }) {
|
|
22
25
|
if (
|
|
@@ -38,7 +41,10 @@ export class ExecutorPageBridge extends ExecutorPageBridgeInterface {
|
|
|
38
41
|
// FIXME: not cloneDeep, create a new instance
|
|
39
42
|
this.feApi = cloneDeep(feApi);
|
|
40
43
|
|
|
41
|
-
this.feApi.
|
|
44
|
+
this.feApi.use({
|
|
45
|
+
pluginName: 'test',
|
|
46
|
+
onSuccess: TestPlugin.onSuccess
|
|
47
|
+
});
|
|
42
48
|
}
|
|
43
49
|
|
|
44
50
|
public override onTestPlugins = async () => {
|
|
@@ -15,6 +15,7 @@ export function LogoutButton() {
|
|
|
15
15
|
const { t } = useAppTranslation();
|
|
16
16
|
const dialogHandler = useIOC(IOCIdentifier.DialogHandler);
|
|
17
17
|
const userService = useIOC(IOCIdentifier.UserServiceInterface);
|
|
18
|
+
const routeService = useIOC(IOCIdentifier.RouteServiceInterface);
|
|
18
19
|
const breakpoint = useBreakpoint();
|
|
19
20
|
const tTitle = t(AUTH_LOGOUT_DIALOG_TITLE);
|
|
20
21
|
const tContent = t(AUTH_LOGOUT_DIALOG_CONTENT);
|
|
@@ -29,7 +30,11 @@ export function LogoutButton() {
|
|
|
29
30
|
'data-testid': 'LogoutButton-CancelButton'
|
|
30
31
|
},
|
|
31
32
|
content: tContent,
|
|
32
|
-
onOk: () =>
|
|
33
|
+
onOk: async () => {
|
|
34
|
+
await userService.logout();
|
|
35
|
+
routeService.reset();
|
|
36
|
+
routeService.gotoLogin();
|
|
37
|
+
}
|
|
33
38
|
});
|
|
34
39
|
}, [tTitle, tContent]);
|
|
35
40
|
|
|
@@ -3,6 +3,7 @@ import { messageBaseListI18n } from '@config/i18n/messageBaseListI18n';
|
|
|
3
3
|
import { I } from '@config/IOCIdentifier';
|
|
4
4
|
import {
|
|
5
5
|
MessageSender,
|
|
6
|
+
MessageSenderExecutor,
|
|
6
7
|
MessagesStore,
|
|
7
8
|
MessageStatus,
|
|
8
9
|
SenderStrategyPlugin,
|
|
@@ -15,7 +16,9 @@ import { useCallback, useMemo, useState } from 'react';
|
|
|
15
16
|
import { useI18nInterface } from '../hooks/useI18nInterface';
|
|
16
17
|
import { useIOC } from '../hooks/useIOC';
|
|
17
18
|
import type {
|
|
19
|
+
GatewayOptions,
|
|
18
20
|
MessageGetwayInterface,
|
|
21
|
+
MessageInterface,
|
|
19
22
|
MessagesStateInterface,
|
|
20
23
|
MessageStoreMsg
|
|
21
24
|
} from '@qlover/corekit-bridge';
|
|
@@ -32,37 +35,46 @@ class MessageBaseApi implements MessageGetwayInterface {
|
|
|
32
35
|
/**
|
|
33
36
|
* @override
|
|
34
37
|
*/
|
|
35
|
-
public async sendMessage<M extends
|
|
36
|
-
message: M
|
|
37
|
-
|
|
38
|
+
public async sendMessage<M extends MessageInterface<unknown>>(
|
|
39
|
+
message: M,
|
|
40
|
+
options?: GatewayOptions<M>
|
|
41
|
+
): Promise<unknown | M> {
|
|
38
42
|
const times = random(200, 1000);
|
|
39
43
|
|
|
40
44
|
await ThreadUtil.sleep(times);
|
|
41
45
|
|
|
42
|
-
const messageContent = message.content ?? '';
|
|
46
|
+
const messageContent = (message as any).content ?? '';
|
|
43
47
|
if (messageContent.includes('Failed') || messageContent.includes('error')) {
|
|
44
|
-
|
|
48
|
+
const error = new Error('Failed to send message');
|
|
49
|
+
await options?.onError?.(error);
|
|
50
|
+
throw error;
|
|
45
51
|
}
|
|
46
52
|
|
|
47
53
|
if (times % 5 === 0) {
|
|
48
|
-
|
|
54
|
+
const error = new Error(`Network error(${times})`);
|
|
55
|
+
await options?.onError?.(error);
|
|
56
|
+
throw error;
|
|
49
57
|
}
|
|
50
58
|
|
|
51
59
|
// Return object response to demonstrate formatting
|
|
52
|
-
|
|
60
|
+
const result = {
|
|
53
61
|
status: 'success',
|
|
54
62
|
timestamp: new Date().toISOString(),
|
|
55
63
|
delay: `${times}ms`,
|
|
56
|
-
echo:
|
|
64
|
+
echo: messageContent,
|
|
57
65
|
data: {
|
|
58
66
|
message: 'Message received successfully',
|
|
59
67
|
processed: true,
|
|
60
68
|
metadata: {
|
|
61
|
-
length:
|
|
69
|
+
length: messageContent?.length || 0,
|
|
62
70
|
type: 'text'
|
|
63
71
|
}
|
|
64
72
|
}
|
|
65
73
|
};
|
|
74
|
+
|
|
75
|
+
options?.onComplete?.(message);
|
|
76
|
+
|
|
77
|
+
return result;
|
|
66
78
|
}
|
|
67
79
|
}
|
|
68
80
|
|
|
@@ -79,7 +91,8 @@ export function MessageBaseList() {
|
|
|
79
91
|
const [messagesSender] = useState(() =>
|
|
80
92
|
new MessageSender<MessageBaseMsg>(messagesStore, {
|
|
81
93
|
gateway: messageBaseApi,
|
|
82
|
-
logger
|
|
94
|
+
logger,
|
|
95
|
+
executor: new MessageSenderExecutor()
|
|
83
96
|
}).use(new SenderStrategyPlugin(SendFailureStrategy.KEEP_FAILED))
|
|
84
97
|
);
|
|
85
98
|
|
|
@@ -220,7 +233,9 @@ export function MessageBaseList() {
|
|
|
220
233
|
<Input
|
|
221
234
|
value={inputValue}
|
|
222
235
|
onPressEnter={onSend}
|
|
223
|
-
onChange={(e) =>
|
|
236
|
+
onChange={(e) =>
|
|
237
|
+
setInputValue((e.target as HTMLInputElement).value)
|
|
238
|
+
}
|
|
224
239
|
placeholder={tt.inputPlaceholder}
|
|
225
240
|
size="large"
|
|
226
241
|
className="flex-1"
|
|
@@ -80,7 +80,9 @@ export function FocusBar({ bridge, tt }: FocusBarProps) {
|
|
|
80
80
|
autoFocus
|
|
81
81
|
value={inputText}
|
|
82
82
|
onKeyDown={handleKeyDown}
|
|
83
|
-
onChange={(e) =>
|
|
83
|
+
onChange={(e) =>
|
|
84
|
+
bridge.onChangeContent((e.target as HTMLTextAreaElement).value)
|
|
85
|
+
}
|
|
84
86
|
placeholder={tt.inputPlaceholder}
|
|
85
87
|
autoSize={{ minRows: 2, maxRows: 6 }}
|
|
86
88
|
className="resize-none"
|
|
@@ -8,7 +8,8 @@ import type {
|
|
|
8
8
|
MessageStoreMsg,
|
|
9
9
|
ChatMessageStore,
|
|
10
10
|
MessageGetwayInterface,
|
|
11
|
-
GatewayOptions
|
|
11
|
+
GatewayOptions,
|
|
12
|
+
MessageInterface
|
|
12
13
|
} from '@qlover/corekit-bridge';
|
|
13
14
|
|
|
14
15
|
export class MessageApi implements MessageGetwayInterface {
|
|
@@ -24,11 +25,13 @@ export class MessageApi implements MessageGetwayInterface {
|
|
|
24
25
|
|
|
25
26
|
* @override
|
|
26
27
|
*/
|
|
27
|
-
public async sendMessage<M extends
|
|
28
|
+
public async sendMessage<M extends MessageInterface<unknown>>(
|
|
28
29
|
message: M,
|
|
29
30
|
options?: GatewayOptions<M>
|
|
30
|
-
): Promise<M> {
|
|
31
|
-
|
|
31
|
+
): Promise<unknown | M> {
|
|
32
|
+
// Type assertion: we expect MessageStoreMsg<string> in this implementation
|
|
33
|
+
const storeMessage = message as unknown as MessageStoreMsg<string>;
|
|
34
|
+
const messageContent = storeMessage.content ?? '';
|
|
32
35
|
|
|
33
36
|
// Check if error simulation is needed
|
|
34
37
|
if (messageContent.includes('Failed') || messageContent.includes('error')) {
|
|
@@ -40,13 +43,19 @@ export class MessageApi implements MessageGetwayInterface {
|
|
|
40
43
|
// Determine which mode to use
|
|
41
44
|
if (options?.stream === true) {
|
|
42
45
|
// Streaming mode: progressive output
|
|
43
|
-
return this.sendStreamMode(
|
|
46
|
+
return this.sendStreamMode(
|
|
47
|
+
storeMessage,
|
|
48
|
+
options as GatewayOptions<MessageStoreMsg<string>>
|
|
49
|
+
) as Promise<unknown | M>;
|
|
44
50
|
} else if (options) {
|
|
45
51
|
// Interruptible normal mode: one-time return, but supports stop
|
|
46
|
-
return this.sendInterruptibleMode(
|
|
52
|
+
return this.sendInterruptibleMode(
|
|
53
|
+
storeMessage,
|
|
54
|
+
options as GatewayOptions<MessageStoreMsg<string>>
|
|
55
|
+
) as Promise<unknown | M>;
|
|
47
56
|
} else {
|
|
48
57
|
// Fast normal mode: non-interruptible
|
|
49
|
-
return this.sendNormalMode(
|
|
58
|
+
return this.sendNormalMode(storeMessage) as Promise<unknown | M>;
|
|
50
59
|
}
|
|
51
60
|
}
|
|
52
61
|
|