@opensumi/ide-core-browser 3.0.4 → 3.0.5-next-1717466130.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.
Files changed (69) hide show
  1. package/lib/ai-native/command.d.ts +6 -0
  2. package/lib/ai-native/command.d.ts.map +1 -1
  3. package/lib/ai-native/command.js +8 -2
  4. package/lib/ai-native/command.js.map +1 -1
  5. package/lib/application/runtime/base-socket.d.ts +9 -1
  6. package/lib/application/runtime/base-socket.d.ts.map +1 -1
  7. package/lib/application/runtime/base-socket.js +34 -4
  8. package/lib/application/runtime/base-socket.js.map +1 -1
  9. package/lib/application/runtime/electron-renderer/socket.d.ts +1 -1
  10. package/lib/application/runtime/index.d.ts +5 -0
  11. package/lib/application/runtime/index.d.ts.map +1 -1
  12. package/lib/application/runtime/index.js +30 -0
  13. package/lib/application/runtime/index.js.map +1 -1
  14. package/lib/bootstrap/app.d.ts +0 -1
  15. package/lib/bootstrap/app.d.ts.map +1 -1
  16. package/lib/bootstrap/app.interface.d.ts +0 -3
  17. package/lib/bootstrap/app.interface.d.ts.map +1 -1
  18. package/lib/bootstrap/app.js +7 -28
  19. package/lib/bootstrap/app.js.map +1 -1
  20. package/lib/bootstrap/connection.d.ts +3 -6
  21. package/lib/bootstrap/connection.d.ts.map +1 -1
  22. package/lib/bootstrap/connection.js +6 -13
  23. package/lib/bootstrap/connection.js.map +1 -1
  24. package/lib/bootstrap/inner-providers.d.ts.map +1 -1
  25. package/lib/bootstrap/inner-providers.js +5 -0
  26. package/lib/bootstrap/inner-providers.js.map +1 -1
  27. package/lib/components/ai-native/ai-action/index.d.ts +6 -0
  28. package/lib/components/ai-native/ai-action/index.d.ts.map +1 -1
  29. package/lib/components/ai-native/ai-action/index.js +33 -16
  30. package/lib/components/ai-native/ai-action/index.js.map +1 -1
  31. package/lib/components/ai-native/ai-action/index.module.less +61 -27
  32. package/lib/components/ai-native/index.d.ts +2 -0
  33. package/lib/components/ai-native/index.d.ts.map +1 -1
  34. package/lib/components/ai-native/index.js +2 -0
  35. package/lib/components/ai-native/index.js.map +1 -1
  36. package/lib/components/ai-native/interactive-input/index.d.ts +14 -0
  37. package/lib/components/ai-native/interactive-input/index.d.ts.map +1 -0
  38. package/lib/components/ai-native/interactive-input/index.js +101 -0
  39. package/lib/components/ai-native/interactive-input/index.js.map +1 -0
  40. package/lib/components/ai-native/interactive-input/index.module.less +54 -0
  41. package/lib/components/ai-native/loading/index.d.ts +5 -0
  42. package/lib/components/ai-native/loading/index.d.ts.map +1 -0
  43. package/lib/components/ai-native/loading/index.js +11 -0
  44. package/lib/components/ai-native/loading/index.js.map +1 -0
  45. package/lib/components/ai-native/loading/index.module.less +16 -0
  46. package/lib/layout/constants.d.ts +0 -1
  47. package/lib/layout/constants.d.ts.map +1 -1
  48. package/lib/layout/constants.js +1 -4
  49. package/lib/layout/constants.js.map +1 -1
  50. package/lib/react-providers/config-provider.d.ts +2 -0
  51. package/lib/react-providers/config-provider.d.ts.map +1 -1
  52. package/lib/react-providers/config-provider.js.map +1 -1
  53. package/package.json +5 -5
  54. package/src/ai-native/command.ts +9 -1
  55. package/src/application/runtime/base-socket.ts +29 -2
  56. package/src/application/runtime/index.ts +38 -0
  57. package/src/bootstrap/app.interface.ts +1 -5
  58. package/src/bootstrap/app.ts +10 -42
  59. package/src/bootstrap/connection.ts +9 -18
  60. package/src/bootstrap/inner-providers.ts +5 -0
  61. package/src/components/ai-native/ai-action/index.module.less +61 -27
  62. package/src/components/ai-native/ai-action/index.tsx +79 -22
  63. package/src/components/ai-native/index.ts +2 -0
  64. package/src/components/ai-native/interactive-input/index.module.less +54 -0
  65. package/src/components/ai-native/interactive-input/index.tsx +204 -0
  66. package/src/components/ai-native/loading/index.module.less +16 -0
  67. package/src/components/ai-native/loading/index.tsx +12 -0
  68. package/src/layout/constants.ts +1 -5
  69. package/src/react-providers/config-provider.tsx +5 -0
@@ -1,9 +1,36 @@
1
+ import { Autowired, INJECTOR_TOKEN, Injectable, Injector } from '@opensumi/di';
2
+ import { WSChannel } from '@opensumi/ide-connection';
3
+ import { WSChannelHandler } from '@opensumi/ide-connection/lib/browser';
1
4
  import { IRuntimeSocketConnection } from '@opensumi/ide-connection/lib/common/connection';
5
+ import { IReporterService, getDebugLogger } from '@opensumi/ide-core-common';
2
6
 
7
+ import { ModuleConstructor, createConnectionService } from '../../bootstrap';
8
+ import { AppConfig } from '../../react-providers';
9
+
10
+ const initialLogger = getDebugLogger();
11
+
12
+ @Injectable({ multiple: true })
3
13
  export abstract class BaseConnectionHelper {
14
+ @Autowired(INJECTOR_TOKEN)
15
+ protected injector: Injector;
16
+
17
+ @Autowired(AppConfig)
18
+ protected appConfig: AppConfig;
19
+
20
+ @Autowired(IReporterService)
21
+ reporterService: IReporterService;
22
+
4
23
  abstract getDefaultClientId(): string;
5
24
 
6
25
  abstract createConnection(): IRuntimeSocketConnection;
7
- }
8
26
 
9
- export const CONNECTION_HELPER_TOKEN = Symbol('CONNECTION_HELPER_TOKEN');
27
+ async createRPCServiceChannel(modules: ModuleConstructor[]): Promise<WSChannel> {
28
+ const connection: IRuntimeSocketConnection<Uint8Array> = this.createConnection();
29
+ const clientId: string = this.appConfig.clientId ?? this.getDefaultClientId();
30
+ const channelHandler = new WSChannelHandler(connection, clientId, {
31
+ logger: initialLogger,
32
+ });
33
+
34
+ return createConnectionService(this.injector, modules, channelHandler);
35
+ }
36
+ }
@@ -1,4 +1,42 @@
1
+ import { Injector } from '@opensumi/di';
2
+
3
+ import { AppConfig } from '../../react-providers';
4
+
5
+ import { BaseConnectionHelper } from './base-socket';
6
+ import { WebConnectionHelper } from './browser/socket';
7
+ import { ESupportRuntime } from './constants';
8
+ import { ElectronConnectionHelper } from './electron-renderer/socket';
9
+
1
10
  export * from './browser/socket';
2
11
  export * from './electron-renderer/socket';
12
+ export * from './base-socket';
3
13
 
4
14
  export * from './constants';
15
+
16
+ export type ConnectionHelperFactory = ReturnType<typeof ConnectionHelperFactory>;
17
+ export function ConnectionHelperFactory(injector: Injector) {
18
+ return (type: string) => {
19
+ const appConfig = injector.get(AppConfig) as AppConfig;
20
+
21
+ let connectionHelper: BaseConnectionHelper;
22
+
23
+ switch (type) {
24
+ case ESupportRuntime.Electron:
25
+ connectionHelper = injector.get(ElectronConnectionHelper);
26
+ break;
27
+ case ESupportRuntime.Web:
28
+ connectionHelper = injector.get(WebConnectionHelper, [
29
+ {
30
+ connectionPath: appConfig.connectionPath,
31
+ connectionProtocols: appConfig.connectionProtocols,
32
+ },
33
+ ]);
34
+ break;
35
+ default: {
36
+ throw new Error(`Unknown backend type: ${type}`);
37
+ }
38
+ }
39
+
40
+ return connectionHelper;
41
+ };
42
+ }
@@ -1,5 +1,4 @@
1
1
  import { ConstructorOf } from '@opensumi/di';
2
- import { UrlProvider } from '@opensumi/ide-core-common';
3
2
 
4
3
  import { BrowserModule } from '../browser-module';
5
4
  import { ClientAppContribution } from '../common/common.define';
@@ -31,10 +30,7 @@ export interface IClientAppOpts extends Partial<AppConfig> {
31
30
  contributions?: ContributionConstructor[];
32
31
  // 前端模块实例声明
33
32
  modulesInstances?: BrowserModule[];
34
- // 自定义前后端通信路径
35
- connectionPath?: UrlProvider;
36
- // 支持的通信协议类型
37
- connectionProtocols?: string[];
33
+
38
34
  // 定义用于 OpenSumi 视图插件内的图标集合
39
35
  iconStyleSheets?: IconInfo[];
40
36
  /**
@@ -6,7 +6,6 @@ import '@opensumi/monaco-editor-core/esm/vs/editor/editor.main';
6
6
 
7
7
  import { Injector } from '@opensumi/di';
8
8
  import { WSChannelHandler } from '@opensumi/ide-connection/lib/browser';
9
- import { IRuntimeSocketConnection } from '@opensumi/ide-connection/lib/common/connection';
10
9
  import {
11
10
  AppLifeCycleServiceToken,
12
11
  CommandRegistry,
@@ -29,7 +28,6 @@ import {
29
28
  StorageResolverContribution,
30
29
  SupportLogNamespace,
31
30
  URI,
32
- UrlProvider,
33
31
  asExtensionCandidate,
34
32
  createContributionProvider,
35
33
  getDebugLogger,
@@ -45,8 +43,8 @@ import {
45
43
  import { IElectronMainLifeCycleService } from '@opensumi/ide-core-common/lib/electron';
46
44
 
47
45
  import { ClientAppStateService } from '../application';
48
- import { ESupportRuntime, ElectronConnectionHelper, WebConnectionHelper } from '../application/runtime';
49
- import { CONNECTION_HELPER_TOKEN } from '../application/runtime/base-socket';
46
+ import { ConnectionHelperFactory, ESupportRuntime } from '../application/runtime';
47
+ import { BaseConnectionHelper } from '../application/runtime/base-socket';
50
48
  import { BrowserRuntime } from '../application/runtime/browser';
51
49
  import { ElectronRendererRuntime } from '../application/runtime/electron-renderer';
52
50
  import { RendererRuntime } from '../application/runtime/types';
@@ -74,7 +72,7 @@ import { electronEnv } from '../utils';
74
72
 
75
73
  import { IClientAppOpts, IPreferences, IconInfo, IconMap, LayoutConfig, ModuleConstructor } from './app.interface';
76
74
  import { IAppRenderer, renderClientApp } from './app.view';
77
- import { bindConnectionServiceDeprecated, createConnectionService } from './connection';
75
+ import { bindConnectionServiceDeprecated } from './connection';
78
76
  import { injectInnerProviders } from './inner-providers';
79
77
 
80
78
  import './polyfills';
@@ -93,7 +91,6 @@ export class ClientApp implements IClientApp, IDisposable {
93
91
  public runtime: ElectronRendererRuntime | BrowserRuntime;
94
92
 
95
93
  private logger: ILogServiceClient;
96
- private connectionPath: UrlProvider;
97
94
  private keybindingRegistry: KeybindingRegistry;
98
95
  private keybindingService: KeybindingService;
99
96
  private modules: ModuleConstructor[];
@@ -106,7 +103,6 @@ export class ClientApp implements IClientApp, IDisposable {
106
103
  constructor(protected opts: IClientAppOpts) {
107
104
  const {
108
105
  modules,
109
- connectionPath,
110
106
  iconStyleSheets,
111
107
  useCdnIcon,
112
108
  editorBackgroundImage,
@@ -145,6 +141,8 @@ export class ClientApp implements IClientApp, IDisposable {
145
141
  rpcMessageTimeout: opts.rpcMessageTimeout || -1,
146
142
  };
147
143
 
144
+ this.config.connectionPath = opts.connectionPath || `${this.config.wsPath}/service`;
145
+
148
146
  const layoutViewSizeConfig = this.injector.get(LayoutViewSizeConfig);
149
147
  layoutViewSizeConfig.init(opts.layoutViewSize);
150
148
  this.config.layoutViewSize = layoutViewSizeConfig;
@@ -176,7 +174,6 @@ export class ClientApp implements IClientApp, IDisposable {
176
174
 
177
175
  this.config = this.runtime.mergeAppConfig(this.config);
178
176
 
179
- this.connectionPath = connectionPath || `${this.config.wsPath}/service`;
180
177
  this.initBaseProvider();
181
178
  this.initFields();
182
179
  this.appendIconStyleSheets(iconStyleSheets, useCdnIcon);
@@ -252,42 +249,13 @@ export class ClientApp implements IClientApp, IDisposable {
252
249
  }
253
250
 
254
251
  protected async createConnection(type: `${ESupportRuntime}`) {
255
- let connectionHelper: ElectronConnectionHelper | WebConnectionHelper;
256
-
257
- switch (type) {
258
- case ESupportRuntime.Electron:
259
- connectionHelper = this.injector.get(ElectronConnectionHelper);
260
- break;
261
- case ESupportRuntime.Web:
262
- connectionHelper = this.injector.get(WebConnectionHelper, [
263
- {
264
- connectionPath: this.connectionPath,
265
- connectionProtocols: this.opts.connectionProtocols,
266
- },
267
- ]);
268
- break;
269
- default:
270
- throw new Error(`Unknown backend type: ${type}`);
271
- }
272
-
273
- this.injector.addProviders({
274
- token: CONNECTION_HELPER_TOKEN,
275
- useValue: connectionHelper,
252
+ const factory = this.injector.get(ConnectionHelperFactory) as ConnectionHelperFactory;
253
+ const connectionHelper: BaseConnectionHelper = factory(type);
254
+ const channel = await connectionHelper.createRPCServiceChannel(this.modules);
255
+ channel.onReopen(() => {
256
+ this.onReconnectContributions();
276
257
  });
277
258
 
278
- const connection: IRuntimeSocketConnection<Uint8Array> = connectionHelper.createConnection();
279
- const clientId: string = this.config.clientId ?? connectionHelper.getDefaultClientId();
280
-
281
- await createConnectionService(
282
- this.injector,
283
- this.modules,
284
- () => {
285
- this.onReconnectContributions();
286
- },
287
- connection,
288
- clientId,
289
- );
290
-
291
259
  // create logger after connection established
292
260
  this.logger = this.getLogger();
293
261
  this.injector.get(WSChannelHandler).replaceLogger(this.logger);
@@ -1,7 +1,7 @@
1
1
  import { Injector, Provider } from '@opensumi/di';
2
- import { RPCServiceCenter, WSChannel, initRPCService } from '@opensumi/ide-connection';
2
+ import { RPCServiceCenter, initRPCService } from '@opensumi/ide-connection';
3
3
  import { WSChannelHandler } from '@opensumi/ide-connection/lib/browser';
4
- import { IRuntimeSocketConnection } from '@opensumi/ide-connection/lib/common/connection';
4
+ import { ISumiConnectionOptions } from '@opensumi/ide-connection/lib/common/rpc/connection';
5
5
  import { RPCServiceChannelPath } from '@opensumi/ide-connection/lib/common/server-handler';
6
6
  import {
7
7
  BasicModule,
@@ -10,7 +10,6 @@ import {
10
10
  BrowserConnectionOpenEvent,
11
11
  IEventBus,
12
12
  IReporterService,
13
- getDebugLogger,
14
13
  } from '@opensumi/ide-core-common';
15
14
  import { BackService } from '@opensumi/ide-core-common/lib/module';
16
15
 
@@ -20,22 +19,18 @@ import { ModuleConstructor } from './app.interface';
20
19
 
21
20
  import type { MessageConnection } from '@opensumi/vscode-jsonrpc/lib/common/connection';
22
21
 
23
- const initialLogger = getDebugLogger();
24
-
25
22
  export async function createConnectionService(
26
23
  injector: Injector,
27
24
  modules: ModuleConstructor[],
28
- onReconnect: () => void,
29
- connection: IRuntimeSocketConnection<Uint8Array>,
30
- clientId: string,
25
+ channelHandler: WSChannelHandler,
26
+ options: ISumiConnectionOptions = {},
31
27
  ) {
32
28
  const reporterService: IReporterService = injector.get(IReporterService);
29
+ channelHandler.setReporter(reporterService);
30
+
33
31
  const eventBus = injector.get(IEventBus);
34
32
  const stateService = injector.get(ClientAppStateService);
35
33
 
36
- const channelHandler = new WSChannelHandler(connection, initialLogger, clientId);
37
- channelHandler.setReporter(reporterService);
38
-
39
34
  const onOpen = () => {
40
35
  stateService.reachedState('core_module_initialized').then(() => {
41
36
  eventBus.fire(new BrowserConnectionOpenEvent());
@@ -71,16 +66,12 @@ export async function createConnectionService(
71
66
  });
72
67
 
73
68
  const channel = await channelHandler.openChannel(RPCServiceChannelPath);
74
- channel.onReopen(() => onReconnect());
75
-
76
- bindConnectionService(injector, modules, channel);
77
- }
78
69
 
79
- export function bindConnectionService(injector: Injector, modules: ModuleConstructor[], channel: WSChannel) {
80
70
  const clientCenter = new RPCServiceCenter();
81
- const disposable = clientCenter.setSumiConnection(channel.createSumiConnection());
71
+ clientCenter.setSumiConnection(channel.createSumiConnection(options));
82
72
  initConnectionService(injector, modules, clientCenter);
83
- return disposable;
73
+
74
+ return channel;
84
75
  }
85
76
 
86
77
  /**
@@ -38,6 +38,7 @@ import {
38
38
  import { AIReporter } from '../ai-native/ai-reporter';
39
39
  import { ClientAppStateService } from '../application/application-state-service';
40
40
  import { ApplicationService } from '../application/application.service';
41
+ import { ConnectionHelperFactory } from '../application/runtime';
41
42
  import { AuthenticationService } from '../authentication/authentication.service';
42
43
  import { ClientAppContribution } from '../common';
43
44
  import { ISplitPanelService, SplitPanelService } from '../components/layout/split-panel.service';
@@ -264,6 +265,10 @@ export function injectInnerProviders(injector: Injector) {
264
265
  token: IDesignStyleService,
265
266
  useClass: DesignStyleService,
266
267
  },
268
+ {
269
+ token: ConnectionHelperFactory,
270
+ useFactory: ConnectionHelperFactory,
271
+ },
267
272
  ];
268
273
  injector.addProviders(...providers);
269
274
  }
@@ -1,45 +1,73 @@
1
- .ai_action {
1
+ @default_height: 24px;
2
+
3
+ .ai_action_wrapper {
2
4
  display: flex;
3
5
  align-items: center;
4
- height: 24px;
5
- padding: 1px 8px;
6
+ padding: 0px 8px;
6
7
  background-color: var(--kt-modal-background);
7
8
  border-radius: 6px;
8
9
  box-shadow: 0px 9px 28px 8px var(--design-boxShadow-primary), 0px 3px 6px -4px var(--design-boxShadow-secondary),
9
10
  0px 6px 16px 0px var(--design-boxShadow-tertiary);
10
11
  font-size: 12px;
11
12
 
12
- .ai_action_icon {
13
- &:hover {
14
- background: var(--design-block-hoverBackground);
13
+ &.loading {
14
+ padding: 0px;
15
+
16
+ .close_container {
17
+ padding-right: 8px;
15
18
  }
16
19
  }
17
20
 
18
- span {
19
- color: var(--design-text-foreground);
21
+ &.loading_show_operation {
22
+ padding: 0px 8px;
23
+
24
+ .close_container {
25
+ padding-right: 0;
26
+ }
27
+
28
+ .operate_container .loading_mask {
29
+ cursor: not-allowed;
30
+ position: absolute;
31
+ z-index: 1;
32
+ left: 18px;
33
+ right: 0;
34
+ height: 100%;
35
+ background-color: var(--kt-input-disableBackground);
36
+ }
20
37
  }
21
38
 
22
- .logo-container {
23
- .avatar {
24
- width: 14px;
25
- height: 14px;
26
- background-image: radial-gradient(circle at 21% 21%, #00f6ff 0%, #9c03ff 95%);
27
- border-radius: 12px;
39
+ .stable_container {
40
+ display: flex;
41
+ align-items: center;
28
42
 
29
- img {
30
- height: 10px;
31
- }
43
+ .loading_icon {
44
+ width: @default_height;
45
+ height: @default_height;
46
+ line-height: @default_height;
32
47
  }
33
48
  }
34
49
 
35
- .operate_container,
36
50
  .close_container {
37
- display: flex;
51
+ display: none;
38
52
  align-items: center;
39
- height: 100%;
53
+ }
54
+
55
+ .ai_action_icon {
56
+ &:hover {
57
+ background: var(--design-block-hoverBackground);
58
+ }
59
+ }
60
+
61
+ span {
62
+ color: var(--design-text-foreground);
40
63
  }
41
64
 
42
65
  .operate_container {
66
+ display: flex;
67
+ align-items: center;
68
+ height: 100%;
69
+ position: relative;
70
+
43
71
  .operate_btn {
44
72
  padding: 3px 4px;
45
73
  border-radius: 4px;
@@ -50,18 +78,24 @@
50
78
  padding: 0 6px;
51
79
  border-radius: 4px;
52
80
  }
81
+ }
53
82
 
83
+ &:hover {
54
84
  .close_container {
55
- display: none;
85
+ display: flex;
56
86
  }
57
87
  }
58
88
 
59
- &:hover {
60
- .operate_container {
61
- .close_container {
62
- display: flex;
63
- }
64
- }
89
+ .custom_operation_wrapper {
90
+ padding: 4px 0px;
91
+ box-sizing: content-box;
92
+ }
93
+
94
+ .default_operation_wrapper {
95
+ display: flex;
96
+ align-items: center;
97
+ height: 100%;
98
+ margin-left: -4px;
65
99
  }
66
100
  }
67
101
 
@@ -1,12 +1,14 @@
1
+ import cls from 'classnames';
1
2
  import React, { useCallback } from 'react';
2
3
 
3
- import { AIInlineChatContentWidgetId } from '@opensumi/ide-core-common';
4
+ import { AIInlineChatContentWidgetId, localize } from '@opensumi/ide-core-common';
4
5
 
5
6
  import { MenuNode } from '../../../menu/next/base';
6
7
  import { createLayoutEventType } from '../../../monaco';
7
8
  import { useChange, useHover } from '../../../react-hooks';
8
9
  import { AILogoAvatar, EnhanceIcon, EnhanceIconWithCtxMenu } from '../enhanceIcon';
9
10
  import { LineVertical } from '../line-vertical';
11
+ import { Loading } from '../loading';
10
12
  import { EnhancePopover } from '../popover';
11
13
 
12
14
  import styles from './index.module.less';
@@ -53,6 +55,12 @@ export interface AIActionProps {
53
55
  showClose?: boolean;
54
56
  onClickItem: (id: string) => void;
55
57
  onClose?: () => void;
58
+ loading?: boolean;
59
+ customOperationRender?: React.ReactNode;
60
+ /**
61
+ * loading 的时候是否继续显示 operation
62
+ */
63
+ loadingShowOperation?: boolean;
56
64
  }
57
65
 
58
66
  const layoutEventType = createLayoutEventType(AIInlineChatContentWidgetId);
@@ -61,28 +69,46 @@ const layoutEvent = new CustomEvent(layoutEventType, {
61
69
  });
62
70
 
63
71
  export const AIAction = (props: AIActionProps) => {
64
- const { operationList, moreOperation, showClose, onClickItem, onClose } = props;
72
+ const {
73
+ operationList,
74
+ moreOperation,
75
+ showClose = true,
76
+ onClickItem,
77
+ onClose,
78
+ customOperationRender,
79
+ loading,
80
+ loadingShowOperation = false,
81
+ } = props;
65
82
 
66
83
  const containerRef = React.useRef<HTMLDivElement>(null);
67
84
  const [ref, isHovered] = useHover<HTMLDivElement>();
68
85
 
69
86
  const handleClose = useCallback(() => {
70
- if (onClose) {
71
- onClose();
72
- }
87
+ onClose?.();
73
88
  }, [onClose]);
74
89
 
75
90
  useChange(isHovered, () => {
76
- if (containerRef.current) {
77
- containerRef.current.dispatchEvent(layoutEvent);
78
- }
91
+ containerRef.current?.dispatchEvent(layoutEvent);
79
92
  });
80
93
 
81
- return (
82
- <div ref={containerRef} className={styles.ai_action}>
83
- <AILogoAvatar className={styles.ai_action_icon} />
84
- <LineVertical height='60%' margin='0px 4px 0 8px' />
85
- <div ref={ref} className={styles.operate_container}>
94
+ /**
95
+ * loading 的遮罩
96
+ */
97
+ const renderLoadingMask = useCallback(() => {
98
+ if (loading && loadingShowOperation) {
99
+ return <div className={styles.loading_mask}></div>;
100
+ }
101
+
102
+ return null;
103
+ }, [loading, loadingShowOperation]);
104
+
105
+ const renderOperation = useCallback(() => {
106
+ if (loading && !loadingShowOperation) {
107
+ return null;
108
+ }
109
+
110
+ const defaultOperationList = (
111
+ <React.Fragment>
86
112
  {operationList.map(({ name, title, id }, i) =>
87
113
  title ? (
88
114
  <EnhancePopover id={id} title={title} key={`popover_${i}`}>
@@ -107,18 +133,49 @@ export const AIAction = (props: AIActionProps) => {
107
133
  }}
108
134
  />
109
135
  ) : null}
110
- {showClose !== false && (
111
- <div
112
- className={styles.close_container}
113
- style={{
114
- display: isHovered ? 'flex' : 'none',
115
- }}
116
- >
117
- <LineVertical height='60%' margin='0px 4px 0 4px' />
136
+ </React.Fragment>
137
+ );
138
+
139
+ return (
140
+ <div ref={ref} className={styles.operate_container}>
141
+ {renderLoadingMask()}
142
+ <LineVertical height='100%' margin='0 8px' maxHeight={14} minHeight={14} />
143
+ {customOperationRender ? (
144
+ <div className={styles.custom_operation_wrapper}>{customOperationRender}</div>
145
+ ) : (
146
+ <div className={styles.default_operation_wrapper}>{defaultOperationList}</div>
147
+ )}
148
+ </div>
149
+ );
150
+ }, [customOperationRender, operationList, moreOperation, loading, loadingShowOperation]);
151
+
152
+ return (
153
+ <div
154
+ ref={containerRef}
155
+ className={cls(
156
+ styles.ai_action_wrapper,
157
+ loading && styles.loading,
158
+ loadingShowOperation && styles.loading_show_operation,
159
+ )}
160
+ >
161
+ <React.Fragment>
162
+ <div className={styles.stable_container}>
163
+ {loading ? (
164
+ <EnhancePopover id={'inline_chat_loading'} title={localize('aiNative.inline.chat.operate.loading.cancel')}>
165
+ <Loading className={styles.loading_icon} />
166
+ </EnhancePopover>
167
+ ) : (
168
+ <AILogoAvatar className={styles.ai_action_icon} />
169
+ )}
170
+ </div>
171
+ {renderOperation()}
172
+ {showClose && (
173
+ <div className={styles.close_container}>
174
+ <LineVertical height='100%' margin='0px 8px' maxHeight={14} minHeight={14} />
118
175
  <EnhanceIcon wrapperClassName={styles.operate_btn} icon={'window-close'} onClick={handleClose} />
119
176
  </div>
120
177
  )}
121
- </div>
178
+ </React.Fragment>
122
179
  </div>
123
180
  );
124
181
  };
@@ -4,3 +4,5 @@ export * from './inline-chat/result';
4
4
  export * from './line-vertical';
5
5
  export * from './popover';
6
6
  export * from './thumbs';
7
+ export * from './loading';
8
+ export * from './interactive-input';
@@ -0,0 +1,54 @@
1
+ .interactive_input_container {
2
+ width: 100%;
3
+ border-radius: 8px;
4
+ padding: 8px 4px 8px 12px;
5
+ font-size: 12px;
6
+ position: relative;
7
+ background-color: transparent;
8
+
9
+ &.active {
10
+ border-color: var(--design-inputOption-activeForeground) !important;
11
+ }
12
+
13
+ textarea {
14
+ resize: none;
15
+ line-height: 16px;
16
+ &::-webkit-scrollbar {
17
+ width: 4px;
18
+ &:hover {
19
+ width: 10px;
20
+ }
21
+ }
22
+ }
23
+
24
+ .input_icon_container {
25
+ .send_chat_btn {
26
+ .send_icon {
27
+ > span {
28
+ &::before {
29
+ font-size: 16px;
30
+ color: var(--design-inputOption-activeForeground);
31
+ }
32
+ }
33
+ }
34
+ &.active .send_icon,
35
+ .send_icon:hover {
36
+ > span {
37
+ &::before {
38
+ color: var(--kt-primaryButton-background);
39
+ }
40
+ }
41
+ }
42
+ }
43
+ }
44
+ }
45
+
46
+ :global {
47
+ .kt-input-addon-after {
48
+ align-items: flex-end;
49
+ margin: 4px 4px 0 0;
50
+ }
51
+ .kt-input-disabled {
52
+ background-color: var(--kt-input-disableBackground) !important;
53
+ }
54
+ }