Skip to content

Commit d17fdd6

Browse files
authored
Merge pull request #481 from easyops-cn/steve/chat-panel
Steve/chat-panel
2 parents b1d6904 + c978291 commit d17fdd6

File tree

6 files changed

+112
-19
lines changed

6 files changed

+112
-19
lines changed

bricks/advanced/src/jsx.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ declare global {
115115
record: Record<string, any>;
116116
}>
117117
) => void;
118+
onRowClick?: (event: CustomEvent<Record<string, any>>) => void;
118119
onExpandedRowsChange?: (
119120
event: CustomEvent<(string | number)[]>
120121
) => void;

bricks/ai-portal/src/chat-input/index.tsx

Lines changed: 56 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
import React, { useCallback, useEffect, useRef, useState } from "react";
1+
import React, {
2+
createRef,
3+
forwardRef,
4+
useCallback,
5+
useEffect,
6+
useImperativeHandle,
7+
useRef,
8+
useState,
9+
} from "react";
210
import { createDecorators, type EventEmitter } from "@next-core/element";
311
import { ReactNextElement, wrapBrick } from "@next-core/react-element";
412
import { TextareaAutoResize } from "@next-shared/form";
@@ -67,7 +75,7 @@ export const WrappedActions = wrapBrick<
6775
onItemDragStart: "item.drag.start",
6876
});
6977

70-
const { defineElement, property, event } = createDecorators();
78+
const { defineElement, property, event, method } = createDecorators();
7179

7280
export interface ChatInputProps {
7381
placeholder?: string;
@@ -92,6 +100,8 @@ export interface ChatInputMapEvents {
92100
onTerminate: "terminate";
93101
}
94102

103+
const ChatInputComponent = forwardRef(LegacyChatInputComponent);
104+
95105
/**
96106
* 小型聊天输入框,用于对话等页面
97107
*/
@@ -160,9 +170,17 @@ class ChatInput extends ReactNextElement implements ChatInputProps {
160170
this.#terminate.emit();
161171
};
162172

173+
#ref = createRef<ChatInputRef>();
174+
175+
@method()
176+
setValue(value: string) {
177+
this.#ref.current?.setValue(value);
178+
}
179+
163180
render() {
164181
return (
165182
<ChatInputComponent
183+
ref={this.#ref}
166184
placeholder={this.placeholder}
167185
autoFocus={this.autoFocus}
168186
submitDisabled={this.submitDisabled}
@@ -181,28 +199,35 @@ class ChatInput extends ReactNextElement implements ChatInputProps {
181199
}
182200
}
183201

202+
interface ChatInputRef {
203+
setValue: (value: string) => void;
204+
}
205+
184206
interface ChatInputComponentProps extends ChatInputProps {
185207
root: HTMLElement;
186208
onMessageSubmit: (value: string) => void;
187209
onChatSubmit: (payload: ChatPayload) => void;
188210
onTerminate: () => void;
189211
}
190212

191-
function ChatInputComponent({
192-
root,
193-
placeholder,
194-
autoFocus,
195-
submitDisabled,
196-
supportsTerminate,
197-
terminating,
198-
uploadOptions,
199-
aiEmployees,
200-
commands,
201-
suggestionsPlacement,
202-
onMessageSubmit,
203-
onChatSubmit,
204-
onTerminate,
205-
}: ChatInputComponentProps) {
213+
function LegacyChatInputComponent(
214+
{
215+
root,
216+
placeholder,
217+
autoFocus,
218+
submitDisabled,
219+
supportsTerminate,
220+
terminating,
221+
uploadOptions,
222+
aiEmployees,
223+
commands,
224+
suggestionsPlacement,
225+
onMessageSubmit,
226+
onChatSubmit,
227+
onTerminate,
228+
}: ChatInputComponentProps,
229+
ref: React.Ref<ChatInputRef>
230+
) {
206231
const containerRef = useRef<HTMLDivElement>(null);
207232

208233
const [wrap, setWrap] = useState(false);
@@ -253,6 +278,20 @@ function ChatInputComponent({
253278
placement: suggestionsPlacement,
254279
});
255280

281+
useImperativeHandle(
282+
ref,
283+
() => ({
284+
setValue: (value: string) => {
285+
valueRef.current = value;
286+
setValue(value);
287+
setTimeout(() => {
288+
textareaRef.current?.focus();
289+
}, 100);
290+
},
291+
}),
292+
[setValue, textareaRef, valueRef]
293+
);
294+
256295
useEffect(() => {
257296
if (!uploadEnabled) {
258297
resetFiles();

bricks/ai-portal/src/chat-panel/index.tsx

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ import { WrappedChatInput, WrappedIcon } from "../shared/bricks";
4444
import { FilePreview } from "../shared/FilePreview/FilePreview.js";
4545
import { ImagesPreview } from "../shared/FilePreview/ImagesPreview.js";
4646
import { TaskContext, type TaskContextValue } from "../shared/TaskContext";
47+
import type { UseBrickConf } from "@next-core/types";
48+
import { ReactUseMultipleBricks } from "@next-core/react-runtime";
4749

4850
const WrappedModal = wrapBrick<
4951
Modal,
@@ -74,6 +76,7 @@ export interface ChatPanelProps {
7476
height?: string | number;
7577
placeholder?: string;
7678
uploadOptions?: UploadOptions;
79+
help?: { useBrick: UseBrickConf };
7780
}
7881

7982
const ChatPanelComponent = forwardRef(LegacyChatPanelComponent);
@@ -105,6 +108,12 @@ class ChatPanel extends ReactNextElement implements ChatPanelProps {
105108
@property({ attribute: false })
106109
accessor uploadOptions: UploadOptions | undefined;
107110

111+
/**
112+
* Show help messages when no conversation exists.
113+
*/
114+
@property({ attribute: false })
115+
accessor help: { useBrick: UseBrickConf } | undefined;
116+
108117
#ref = createRef<ChatPanelRef>();
109118

110119
@method()
@@ -117,6 +126,11 @@ class ChatPanel extends ReactNextElement implements ChatPanelProps {
117126
this.#ref.current?.close();
118127
}
119128

129+
@method()
130+
setInputValue(content: string) {
131+
this.#ref.current?.setInputValue(content);
132+
}
133+
120134
@method()
121135
send(payload: ChatPayload) {
122136
this.#ref.current?.send(payload);
@@ -138,6 +152,7 @@ class ChatPanel extends ReactNextElement implements ChatPanelProps {
138152
height={this.height}
139153
placeholder={this.placeholder}
140154
uploadOptions={this.uploadOptions}
155+
help={this.help}
141156
/>
142157
);
143158
}
@@ -151,6 +166,7 @@ interface ChatPanelComponentProps extends ChatPanelProps {
151166
interface ChatPanelRef {
152167
open: () => void;
153168
close: () => void;
169+
setInputValue: (content: string) => void;
154170
send: (payload: ChatPayload) => void;
155171
showFile: (file: FileInfo) => void;
156172
}
@@ -164,6 +180,7 @@ function LegacyChatPanelComponent(
164180
height,
165181
placeholder,
166182
uploadOptions,
183+
help,
167184
}: ChatPanelComponentProps,
168185
ref: React.Ref<ChatPanelRef>
169186
) {
@@ -286,6 +303,9 @@ function LegacyChatPanelComponent(
286303
close: () => {
287304
modalRef.current?.close();
288305
},
306+
setInputValue: (content: string) => {
307+
inputRef.current?.setValue(content);
308+
},
289309
send: (payload: ChatPayload) => {
290310
handleChatSubmit(payload);
291311
},
@@ -317,7 +337,11 @@ function LegacyChatPanelComponent(
317337
>
318338
<div className={styles.panel}>
319339
{!conversationId ? (
320-
<div className={styles.main} />
340+
<div className={styles.main}>
341+
{help ? (
342+
<ReactUseMultipleBricks useBrick={help.useBrick} />
343+
) : null}
344+
</div>
321345
) : conversationAvailable && depsReady ? (
322346
<div className={styles.main}>
323347
<div className={styles.chat} ref={scrollContainerRef}>

bricks/ai-portal/src/jsx.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,11 @@ declare global {
345345
HTMLAttributes<ChatPanel>,
346346
ChatPanel
347347
> &
348-
ChatPanelProps;
348+
Omit<ChatPanelProps, "help"> & {
349+
help?: {
350+
render: () => React.ReactNode;
351+
};
352+
};
349353
}
350354
}
351355
}

bricks/ai-portal/src/shared/ReadableCommand/ReadableCommand.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ export function getInitialContent(
8282
.slice(0, 1)
8383
.map((name) => `: ${name}`)
8484
.join("")}`;
85+
case "serviceObject-createOrEdit":
86+
return `/manage business object`;
87+
case "serviceObjectInstance-createOrEdit":
88+
return `/manage business object instance`;
8589
default:
8690
// unknown command type
8791
return `/${(cmd as CommandPayload).type}`;

bricks/ai-portal/src/shared/interfaces.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,8 @@ export type CommandPayload =
282282
| CommandPayloadServiceFlowCreate
283283
| CommandPayloadServiceFlowEdit
284284
| CommandPayloadGoalPlan
285+
| CommandPayloadBusinessObjectManagement
286+
| CommandPayloadBusinessInstanceManagement
285287
| LegacyCommandPayloadServiceFlowStarting;
286288

287289
export interface BaseCommandPayload {
@@ -326,6 +328,25 @@ export interface CommandPayloadGoalPlan extends BaseCommandPayload {
326328
};
327329
}
328330

331+
export interface CommandPayloadBusinessObjectManagement
332+
extends BaseCommandPayload {
333+
type: "serviceObject-createOrEdit";
334+
payload: {
335+
spaceInstanceId: string;
336+
serviceObjectId?: string;
337+
};
338+
}
339+
340+
export interface CommandPayloadBusinessInstanceManagement
341+
extends BaseCommandPayload {
342+
type: "serviceObjectInstance-createOrEdit";
343+
payload: {
344+
spaceInstanceId: string;
345+
serviceObjectId: string;
346+
instanceId?: string;
347+
};
348+
}
349+
329350
/** @deprecated Use `payload` instead */
330351
export interface LegacyCommandPayloadServiceFlowStarting {
331352
type: "serviceFlowStarting";

0 commit comments

Comments
 (0)