@autobe/ui 0.20.0 → 0.21.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/lib/AutoBeChatMain.d.ts +16 -0
- package/lib/AutoBeChatMain.js +51 -0
- package/lib/AutoBeChatMain.js.map +1 -0
- package/lib/banner/AutoBeAgentInformation.d.ts +15 -0
- package/lib/banner/AutoBeAgentInformation.js +41 -0
- package/lib/banner/AutoBeAgentInformation.js.map +1 -0
- package/lib/banner/AutoBeChatBanner.d.ts +15 -0
- package/lib/banner/AutoBeChatBanner.js +29 -0
- package/lib/banner/AutoBeChatBanner.js.map +1 -0
- package/lib/banner/AutoBeChatState.d.ts +6 -0
- package/lib/banner/AutoBeChatState.js +80 -0
- package/lib/banner/AutoBeChatState.js.map +1 -0
- package/lib/banner/AutoBeTokenUsage.d.ts +14 -0
- package/lib/banner/AutoBeTokenUsage.js +60 -0
- package/lib/banner/AutoBeTokenUsage.js.map +1 -0
- package/lib/banner/index.d.ts +4 -0
- package/lib/banner/index.js +21 -0
- package/lib/banner/index.js.map +1 -0
- package/lib/common/Collapsible.d.ts +15 -0
- package/lib/common/Collapsible.js +45 -0
- package/lib/common/Collapsible.js.map +1 -0
- package/lib/common/index.d.ts +2 -0
- package/lib/common/index.js +19 -0
- package/lib/common/index.js.map +1 -0
- package/lib/constant/color.d.ts +18 -0
- package/lib/constant/color.js +25 -0
- package/lib/constant/color.js.map +1 -0
- package/lib/events/AutoBeEventMovie.d.ts +8 -0
- package/lib/events/AutoBeEventMovie.js +84 -0
- package/lib/events/AutoBeEventMovie.js.map +1 -0
- package/lib/events/index.d.ts +2 -1
- package/lib/events/index.js +5 -3
- package/lib/events/index.js.map +1 -1
- package/lib/hooks/index.d.ts +2 -0
- package/lib/hooks/index.js +19 -0
- package/lib/hooks/index.js.map +1 -0
- package/lib/hooks/useIsomorphicLayoutEffect.d.ts +6 -0
- package/lib/hooks/useIsomorphicLayoutEffect.js +10 -0
- package/lib/hooks/useIsomorphicLayoutEffect.js.map +1 -0
- package/lib/hooks/useMediaQuery.d.ts +11 -0
- package/lib/hooks/useMediaQuery.js +52 -0
- package/lib/hooks/useMediaQuery.js.map +1 -0
- package/lib/index.d.ts +5 -3
- package/lib/index.js +8 -7
- package/lib/index.js.map +1 -1
- package/lib/structure/AutoBeListener.d.ts +17 -0
- package/lib/structure/AutoBeListener.js +250 -0
- package/lib/structure/AutoBeListener.js.map +1 -0
- package/lib/structure/AutoBeListenerState.d.ts +14 -0
- package/lib/structure/AutoBeListenerState.js +39 -0
- package/lib/structure/AutoBeListenerState.js.map +1 -0
- package/lib/structure/IAutoBeEventGroup.d.ts +5 -0
- package/lib/structure/IAutoBeEventGroup.js +3 -0
- package/lib/structure/IAutoBeEventGroup.js.map +1 -0
- package/lib/structure/index.d.ts +3 -0
- package/lib/structure/index.js +20 -0
- package/lib/structure/index.js.map +1 -0
- package/lib/upload/AutoBeChatUploadBox.d.ts +31 -0
- package/lib/upload/AutoBeChatUploadBox.js +221 -0
- package/lib/upload/AutoBeChatUploadBox.js.map +1 -0
- package/lib/upload/AutoBeChatUploadSendButton.js.map +1 -0
- package/lib/upload/AutoBeFileUploadBox.d.ts +8 -0
- package/lib/upload/AutoBeFileUploadBox.js.map +1 -0
- package/lib/upload/AutoBeUploadConfig.d.ts +9 -0
- package/lib/upload/AutoBeUploadConfig.js +3 -0
- package/lib/upload/AutoBeUploadConfig.js.map +1 -0
- package/lib/{AutoBeVoiceRecoderButton.js → upload/AutoBeVoiceRecoderButton.js} +2 -2
- package/lib/upload/AutoBeVoiceRecoderButton.js.map +1 -0
- package/lib/upload/index.d.ts +5 -0
- package/lib/upload/index.js +22 -0
- package/lib/upload/index.js.map +1 -0
- package/lib/utils/index.d.ts +1 -0
- package/lib/utils/index.js +1 -0
- package/lib/utils/index.js.map +1 -1
- package/lib/utils/number.d.ts +1 -0
- package/lib/utils/number.js +20 -0
- package/lib/utils/number.js.map +1 -0
- package/package.json +6 -10
- package/src/AutoBeChatMain.tsx +123 -0
- package/src/banner/AutoBeAgentInformation.tsx +102 -0
- package/src/banner/AutoBeChatBanner.tsx +72 -0
- package/src/banner/AutoBeChatState.tsx +152 -0
- package/src/banner/AutoBeTokenUsage.tsx +152 -0
- package/src/banner/index.ts +4 -0
- package/src/common/Collapsible.tsx +95 -0
- package/src/common/index.ts +2 -0
- package/src/constant/color.ts +24 -0
- package/src/events/AutoBeEventMovie.tsx +114 -0
- package/src/events/README.md +150 -19
- package/src/events/index.ts +2 -4
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useIsomorphicLayoutEffect.ts +8 -0
- package/src/hooks/useMediaQuery.ts +68 -0
- package/src/index.ts +5 -6
- package/src/structure/AutoBeListener.ts +263 -0
- package/src/structure/AutoBeListenerState.ts +53 -0
- package/src/structure/IAutoBeEventGroup.ts +6 -0
- package/src/structure/index.ts +3 -0
- package/src/upload/AutoBeChatUploadBox.tsx +372 -0
- package/src/{AutoBeFileUploadBox.tsx → upload/AutoBeFileUploadBox.tsx} +7 -8
- package/src/upload/AutoBeUploadConfig.ts +5 -0
- package/src/{AutoBeVoiceRecoderButton.tsx → upload/AutoBeVoiceRecoderButton.tsx} +2 -2
- package/src/upload/index.ts +5 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/number.ts +17 -0
- package/tsconfig.json +2 -1
- package/lib/AutoBeChatUploadSendButton.js.map +0 -1
- package/lib/AutoBeFileUploadBox.d.ts +0 -10
- package/lib/AutoBeFileUploadBox.js.map +0 -1
- package/lib/AutoBeVoiceRecoderButton.js.map +0 -1
- /package/lib/{AutoBeChatUploadSendButton.d.ts → upload/AutoBeChatUploadSendButton.d.ts} +0 -0
- /package/lib/{AutoBeChatUploadSendButton.js → upload/AutoBeChatUploadSendButton.js} +0 -0
- /package/lib/{AutoBeFileUploadBox.js → upload/AutoBeFileUploadBox.js} +0 -0
- /package/lib/{AutoBeVoiceRecoderButton.d.ts → upload/AutoBeVoiceRecoderButton.d.ts} +0 -0
- /package/src/{AutoBeChatUploadSendButton.tsx → upload/AutoBeChatUploadSendButton.tsx} +0 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AutoBeUserMessageContent,
|
|
3
|
+
IAutoBePlaygroundHeader,
|
|
4
|
+
IAutoBeRpcService,
|
|
5
|
+
IAutoBeTokenUsageJson,
|
|
6
|
+
} from "@autobe/interface";
|
|
7
|
+
import { ILlmSchema } from "@samchon/openapi";
|
|
8
|
+
import { RefObject, useEffect, useRef } from "react";
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
AutoBeChatBanner,
|
|
12
|
+
AutoBeChatUploadBox,
|
|
13
|
+
AutoBeEventMovie,
|
|
14
|
+
AutoBeListenerState,
|
|
15
|
+
IAutoBeEventGroup,
|
|
16
|
+
IAutoBeUploadConfig,
|
|
17
|
+
} from ".";
|
|
18
|
+
import { useMediaQuery } from "./hooks";
|
|
19
|
+
|
|
20
|
+
export interface IAutoBeChatMainProps {
|
|
21
|
+
isMobile: boolean;
|
|
22
|
+
eventGroups: IAutoBeEventGroup[];
|
|
23
|
+
service: IAutoBeRpcService;
|
|
24
|
+
conversate: (messages: AutoBeUserMessageContent[]) => Promise<void>;
|
|
25
|
+
setError: (error: Error) => void;
|
|
26
|
+
uploadConfig?: IAutoBeUploadConfig;
|
|
27
|
+
tokenUsage: IAutoBeTokenUsageJson | null;
|
|
28
|
+
header: IAutoBePlaygroundHeader<ILlmSchema.Model>;
|
|
29
|
+
state: AutoBeListenerState;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export const AutoBeChatMain = (props: IAutoBeChatMainProps) => {
|
|
33
|
+
const bodyContainerRef = useRef<HTMLDivElement>(null);
|
|
34
|
+
const scrollAnchorRef = useRef<HTMLDivElement>(null);
|
|
35
|
+
|
|
36
|
+
const listener: RefObject<AutoBeChatUploadBox.IListener> = useRef({
|
|
37
|
+
handleDragEnter: () => {},
|
|
38
|
+
handleDragLeave: () => {},
|
|
39
|
+
handleDrop: () => {},
|
|
40
|
+
handleDragOver: () => {},
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
useEffect(() => {
|
|
44
|
+
if (props.eventGroups.length === 0) return;
|
|
45
|
+
scrollAnchorRef.current?.scrollIntoView({
|
|
46
|
+
behavior: "smooth",
|
|
47
|
+
});
|
|
48
|
+
}, [bodyContainerRef.current?.scrollHeight]);
|
|
49
|
+
|
|
50
|
+
const isMinWidthLg = useMediaQuery(useMediaQuery.MIN_WIDTH_LG);
|
|
51
|
+
return (
|
|
52
|
+
<div
|
|
53
|
+
onDragEnter={(e) => listener.current.handleDragEnter(e)}
|
|
54
|
+
onDragLeave={(e) => listener.current.handleDragLeave(e)}
|
|
55
|
+
onDragOver={(e) => listener.current.handleDragOver(e)}
|
|
56
|
+
onDrop={(e) => listener.current.handleDrop(e)}
|
|
57
|
+
style={{
|
|
58
|
+
position: "relative",
|
|
59
|
+
overflowY: "auto",
|
|
60
|
+
margin: 0,
|
|
61
|
+
backgroundColor: "lightblue",
|
|
62
|
+
flexGrow: 1,
|
|
63
|
+
display: "flex",
|
|
64
|
+
flexDirection: "column",
|
|
65
|
+
}}
|
|
66
|
+
ref={bodyContainerRef}
|
|
67
|
+
>
|
|
68
|
+
{!isMinWidthLg && (
|
|
69
|
+
<AutoBeChatBanner
|
|
70
|
+
header={props.header}
|
|
71
|
+
tokenUsage={props.tokenUsage}
|
|
72
|
+
state={props.state}
|
|
73
|
+
/>
|
|
74
|
+
)}
|
|
75
|
+
|
|
76
|
+
<div
|
|
77
|
+
style={{
|
|
78
|
+
backgroundColor: "lightblue",
|
|
79
|
+
padding: "2rem",
|
|
80
|
+
gap: 16,
|
|
81
|
+
display: "flex",
|
|
82
|
+
flexDirection: "column",
|
|
83
|
+
}}
|
|
84
|
+
>
|
|
85
|
+
{props.eventGroups.map((e, index) => (
|
|
86
|
+
<AutoBeEventMovie
|
|
87
|
+
key={index}
|
|
88
|
+
getFiles={props.service.getFiles}
|
|
89
|
+
events={e.events}
|
|
90
|
+
last={index === props.eventGroups.length - 1}
|
|
91
|
+
/>
|
|
92
|
+
))}
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
{/*
|
|
96
|
+
* Prompt input area
|
|
97
|
+
* this flexGrow: 1 means that the prompt input area will take up the remaining space
|
|
98
|
+
* so that the upload box will be at the bottom of the screen
|
|
99
|
+
*/}
|
|
100
|
+
<div
|
|
101
|
+
style={{ flexGrow: 1, minHeight: "1rem" }}
|
|
102
|
+
ref={scrollAnchorRef}
|
|
103
|
+
></div>
|
|
104
|
+
<div
|
|
105
|
+
style={{
|
|
106
|
+
position: "sticky",
|
|
107
|
+
bottom: 16,
|
|
108
|
+
left: 0,
|
|
109
|
+
right: 0,
|
|
110
|
+
zIndex: 1000,
|
|
111
|
+
}}
|
|
112
|
+
>
|
|
113
|
+
<AutoBeChatUploadBox
|
|
114
|
+
listener={listener}
|
|
115
|
+
uploadConfig={props.uploadConfig}
|
|
116
|
+
conversate={props.conversate}
|
|
117
|
+
setError={props.setError}
|
|
118
|
+
/>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
);
|
|
122
|
+
};
|
|
123
|
+
export default AutoBeChatMain;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import {
|
|
2
|
+
IAutoBePlaygroundHeader,
|
|
3
|
+
IAutoBePlaygroundVendor,
|
|
4
|
+
} from "@autobe/interface";
|
|
5
|
+
import { ILlmSchema } from "@samchon/openapi";
|
|
6
|
+
import { ReactNode } from "react";
|
|
7
|
+
|
|
8
|
+
import { COLORS } from "../constant/color";
|
|
9
|
+
|
|
10
|
+
export interface IAutoBeAgentInformationProps {
|
|
11
|
+
header: Omit<IAutoBePlaygroundHeader<ILlmSchema.Model>, "vendor"> & {
|
|
12
|
+
vendor: Omit<IAutoBePlaygroundVendor, "apiKey">;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Props interface for InfoRow component */
|
|
17
|
+
interface IInfoRowProps {
|
|
18
|
+
/** Label text */
|
|
19
|
+
label: string;
|
|
20
|
+
/** Value to display */
|
|
21
|
+
value: ReactNode;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Props interface for InfoLabel component */
|
|
25
|
+
interface IInfoLabelProps {
|
|
26
|
+
/** Label text */
|
|
27
|
+
children: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Props interface for InfoValue component */
|
|
31
|
+
interface IInfoValueProps {
|
|
32
|
+
/** Value content */
|
|
33
|
+
children: ReactNode;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Info row component with consistent flex layout */
|
|
37
|
+
const InfoRow = ({ label, value }: IInfoRowProps) => (
|
|
38
|
+
<div
|
|
39
|
+
style={{
|
|
40
|
+
display: "flex",
|
|
41
|
+
alignItems: "center",
|
|
42
|
+
padding: "4px 0",
|
|
43
|
+
gap: "8px",
|
|
44
|
+
}}
|
|
45
|
+
>
|
|
46
|
+
<InfoLabel>{label + ":"}</InfoLabel>
|
|
47
|
+
<InfoValue>{value}</InfoValue>
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
/** Info label component with consistent styling */
|
|
52
|
+
const InfoLabel = ({ children }: IInfoLabelProps) => (
|
|
53
|
+
<span
|
|
54
|
+
style={{
|
|
55
|
+
color: COLORS.GRAY_TEXT_MEDIUM,
|
|
56
|
+
fontWeight: "500",
|
|
57
|
+
fontSize: "0.875rem",
|
|
58
|
+
}}
|
|
59
|
+
>
|
|
60
|
+
{children}
|
|
61
|
+
</span>
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
/** Info value component with styling */
|
|
65
|
+
const InfoValue = ({ children }: IInfoValueProps) => (
|
|
66
|
+
<span
|
|
67
|
+
style={{
|
|
68
|
+
color: COLORS.GRAY_TEXT_DARK,
|
|
69
|
+
fontWeight: "600",
|
|
70
|
+
fontSize: "0.875rem",
|
|
71
|
+
}}
|
|
72
|
+
>
|
|
73
|
+
{children}
|
|
74
|
+
</span>
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Agent information component displaying model, locale, and configuration
|
|
79
|
+
* details
|
|
80
|
+
*
|
|
81
|
+
* @param props - Component props
|
|
82
|
+
* @returns JSX element representing the agent information
|
|
83
|
+
*/
|
|
84
|
+
export const AutoBeAgentInformation = ({
|
|
85
|
+
header,
|
|
86
|
+
}: IAutoBeAgentInformationProps) => {
|
|
87
|
+
return (
|
|
88
|
+
<div
|
|
89
|
+
style={{
|
|
90
|
+
display: "flex",
|
|
91
|
+
flexDirection: "column",
|
|
92
|
+
gap: "6px",
|
|
93
|
+
}}
|
|
94
|
+
>
|
|
95
|
+
<InfoRow label="AI Model" value={header.vendor.model} />
|
|
96
|
+
<InfoRow label="Schema Model" value={header.model} />
|
|
97
|
+
<InfoRow label="Locale" value={header.locale} />
|
|
98
|
+
<InfoRow label="Timezone" value={header.timezone} />
|
|
99
|
+
<InfoRow label="Semaphore" value={header.vendor.semaphore ?? 16} />
|
|
100
|
+
</div>
|
|
101
|
+
);
|
|
102
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { IAutoBeTokenUsageJson } from "@autobe/interface";
|
|
2
|
+
|
|
3
|
+
import { Collapsible } from "../common";
|
|
4
|
+
import { COLORS, SHADOWS } from "../constant/color";
|
|
5
|
+
import {
|
|
6
|
+
AutoBeAgentInformation,
|
|
7
|
+
IAutoBeAgentInformationProps,
|
|
8
|
+
} from "./AutoBeAgentInformation";
|
|
9
|
+
import { AutoBeChatState, IAutoBeChatStateProps } from "./AutoBeChatState";
|
|
10
|
+
import { AutoBeTokenUsage } from "./AutoBeTokenUsage";
|
|
11
|
+
|
|
12
|
+
/** Props interface for AutoBeChatBanner component */
|
|
13
|
+
interface IAutoBeChatBannerProps {
|
|
14
|
+
/** Agent information to display */
|
|
15
|
+
header: IAutoBeAgentInformationProps["header"];
|
|
16
|
+
|
|
17
|
+
/** Token usage data to display */
|
|
18
|
+
tokenUsage: IAutoBeTokenUsageJson | null;
|
|
19
|
+
|
|
20
|
+
/** Chat state to display */
|
|
21
|
+
state: IAutoBeChatStateProps["state"];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Chat banner component with collapsible token usage display */
|
|
25
|
+
export const AutoBeChatBanner = (props: IAutoBeChatBannerProps) => {
|
|
26
|
+
return (
|
|
27
|
+
<header
|
|
28
|
+
style={{
|
|
29
|
+
padding: "0 48",
|
|
30
|
+
position: "sticky",
|
|
31
|
+
top: "12px",
|
|
32
|
+
marginBottom: "1rem",
|
|
33
|
+
zIndex: 10,
|
|
34
|
+
}}
|
|
35
|
+
>
|
|
36
|
+
<div
|
|
37
|
+
style={{
|
|
38
|
+
border: `1px solid ${COLORS.GRAY_BORDER}`,
|
|
39
|
+
borderRadius: "8px",
|
|
40
|
+
backgroundColor: COLORS.GRAY_BACKGROUND,
|
|
41
|
+
padding: "0 16px 16px 16px",
|
|
42
|
+
boxShadow: SHADOWS.CARD,
|
|
43
|
+
width: "100%",
|
|
44
|
+
}}
|
|
45
|
+
>
|
|
46
|
+
<h3>Summaries</h3>
|
|
47
|
+
|
|
48
|
+
<Collapsible
|
|
49
|
+
title="Agent Information"
|
|
50
|
+
defaultCollapsed={true}
|
|
51
|
+
animated={true}
|
|
52
|
+
>
|
|
53
|
+
<AutoBeAgentInformation header={props.header} />
|
|
54
|
+
</Collapsible>
|
|
55
|
+
<br />
|
|
56
|
+
<Collapsible
|
|
57
|
+
title="Token Usage"
|
|
58
|
+
defaultCollapsed={false}
|
|
59
|
+
animated={true}
|
|
60
|
+
>
|
|
61
|
+
<AutoBeTokenUsage tokenUsage={props.tokenUsage} />
|
|
62
|
+
</Collapsible>
|
|
63
|
+
<br />
|
|
64
|
+
<Collapsible title="Chat State" defaultCollapsed={true} animated={true}>
|
|
65
|
+
<AutoBeChatState state={props.state} />
|
|
66
|
+
</Collapsible>
|
|
67
|
+
</div>
|
|
68
|
+
</header>
|
|
69
|
+
);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export default AutoBeChatBanner;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AutoBeAnalyzeCompleteEvent,
|
|
3
|
+
AutoBeInterfaceCompleteEvent,
|
|
4
|
+
AutoBePrismaCompleteEvent,
|
|
5
|
+
AutoBeRealizeCompleteEvent,
|
|
6
|
+
AutoBeTestCompleteEvent,
|
|
7
|
+
} from "@autobe/interface";
|
|
8
|
+
|
|
9
|
+
import { AutoBeListenerState } from "..";
|
|
10
|
+
import { COLORS } from "../constant/color";
|
|
11
|
+
|
|
12
|
+
export interface IAutoBeChatStateProps {
|
|
13
|
+
state: AutoBeListenerState;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Common styles for step items */
|
|
17
|
+
const getStepItemStyle = (isActive: boolean): React.CSSProperties => ({
|
|
18
|
+
padding: "12px",
|
|
19
|
+
backgroundColor: COLORS.GRAY_BACKGROUND,
|
|
20
|
+
borderRadius: "6px",
|
|
21
|
+
borderLeft: `4px solid ${isActive ? "#007bff" : COLORS.GRAY_BORDER}`,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const stepTitleStyle: React.CSSProperties = {
|
|
25
|
+
fontWeight: "bold",
|
|
26
|
+
fontSize: "0.9rem",
|
|
27
|
+
marginBottom: "4px",
|
|
28
|
+
color: COLORS.GRAY_TEXT_DARK,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const stepDataStyle: React.CSSProperties = {
|
|
32
|
+
fontSize: "0.85rem",
|
|
33
|
+
color: COLORS.GRAY_TEXT_MEDIUM,
|
|
34
|
+
lineHeight: "1.4",
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/** Props interface for StateStep component */
|
|
38
|
+
interface IStateStepProps {
|
|
39
|
+
/** Step name */
|
|
40
|
+
step: string;
|
|
41
|
+
|
|
42
|
+
data:
|
|
43
|
+
| AutoBeAnalyzeCompleteEvent
|
|
44
|
+
| AutoBePrismaCompleteEvent
|
|
45
|
+
| AutoBeInterfaceCompleteEvent
|
|
46
|
+
| AutoBeTestCompleteEvent
|
|
47
|
+
| AutoBeRealizeCompleteEvent;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Component for displaying active state step */
|
|
51
|
+
const StateStep = ({ step, data }: IStateStepProps) => (
|
|
52
|
+
<div style={getStepItemStyle(true)}>
|
|
53
|
+
<div
|
|
54
|
+
style={stepTitleStyle}
|
|
55
|
+
>{`${step.charAt(0).toUpperCase()}${step.slice(1)}`}</div>
|
|
56
|
+
<div style={stepDataStyle}>
|
|
57
|
+
{Object.entries(getStepCount(data))
|
|
58
|
+
.map(([key, value]) => `${key}: ${value.toLocaleString()}`)
|
|
59
|
+
.join(" • ")}
|
|
60
|
+
</div>
|
|
61
|
+
<div style={stepDataStyle}>
|
|
62
|
+
⏱️ {(Math.floor((data.elapsed / 60_000) * 100) / 100).toLocaleString()}{" "}
|
|
63
|
+
mins
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
/** Component for displaying empty state step */
|
|
69
|
+
const StateEmpty = ({ step }: { step: string }) => (
|
|
70
|
+
<div style={getStepItemStyle(false)}>
|
|
71
|
+
<div
|
|
72
|
+
style={stepTitleStyle}
|
|
73
|
+
>{`${step.charAt(0).toUpperCase()}${step.slice(1)}`}</div>
|
|
74
|
+
<div style={stepDataStyle}>0 items • ⏱️ 0 mins</div>
|
|
75
|
+
</div>
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
/** Component to display development state information */
|
|
79
|
+
export const AutoBeChatState = (props: IAutoBeChatStateProps) => {
|
|
80
|
+
const containerStyle: React.CSSProperties = {
|
|
81
|
+
display: "flex",
|
|
82
|
+
flexDirection: "column",
|
|
83
|
+
gap: "12px",
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const steps = ["analyze", "prisma", "interface", "test", "realize"] as const;
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<div style={containerStyle}>
|
|
90
|
+
<div style={{ display: "flex", flexDirection: "column", gap: "8px" }}>
|
|
91
|
+
{steps.map((stepType) =>
|
|
92
|
+
props.state[stepType] ? (
|
|
93
|
+
<StateStep
|
|
94
|
+
key={stepType}
|
|
95
|
+
step={stepType}
|
|
96
|
+
data={props.state[stepType]}
|
|
97
|
+
/>
|
|
98
|
+
) : (
|
|
99
|
+
<StateEmpty key={stepType} step={stepType} />
|
|
100
|
+
),
|
|
101
|
+
)}
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
);
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/** Calculate count data based on step type */
|
|
108
|
+
const getStepCount = (
|
|
109
|
+
data:
|
|
110
|
+
| AutoBeAnalyzeCompleteEvent
|
|
111
|
+
| AutoBePrismaCompleteEvent
|
|
112
|
+
| AutoBeInterfaceCompleteEvent
|
|
113
|
+
| AutoBeTestCompleteEvent
|
|
114
|
+
| AutoBeRealizeCompleteEvent,
|
|
115
|
+
): Record<string, number> => {
|
|
116
|
+
switch (data.type) {
|
|
117
|
+
case "analyzeComplete": {
|
|
118
|
+
return {
|
|
119
|
+
Documents: Object.keys(data.files).length,
|
|
120
|
+
"Actor Roles": data.roles.length,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
case "prismaComplete": {
|
|
124
|
+
return {
|
|
125
|
+
Namespaces: data.result.data.files.length,
|
|
126
|
+
Models: data.result.data.files
|
|
127
|
+
.map((f: { models: unknown[] }) => f.models.length)
|
|
128
|
+
.reduce((a: number, b: number) => a + b, 0),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
case "interfaceComplete": {
|
|
132
|
+
return {
|
|
133
|
+
Operations: data.document.operations.length,
|
|
134
|
+
Schemas: Object.keys(data.document.components.schemas).length,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
case "testComplete": {
|
|
138
|
+
return {
|
|
139
|
+
Functions: data.files.length,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
case "realizeComplete": {
|
|
143
|
+
return {
|
|
144
|
+
Controllers: Object.keys(data.controllers).length,
|
|
145
|
+
Functions: data.functions.length,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
default:
|
|
149
|
+
data satisfies never;
|
|
150
|
+
throw new Error(`Unknown step type: ${data}`);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { IAutoBeTokenUsageJson } from "@autobe/interface";
|
|
2
|
+
import { ReactNode } from "react";
|
|
3
|
+
|
|
4
|
+
import { COLORS } from "../constant/color";
|
|
5
|
+
import { toCompactNumberFormat } from "../utils";
|
|
6
|
+
|
|
7
|
+
/** Props interface for TokenUsageCard component */
|
|
8
|
+
interface ITokenUsageCardProps {
|
|
9
|
+
/** Token usage data to display */
|
|
10
|
+
tokenUsage: IAutoBeTokenUsageJson | null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Props interface for TokenRow component */
|
|
14
|
+
interface ITokenRowProps {
|
|
15
|
+
/** Label text */
|
|
16
|
+
label: string;
|
|
17
|
+
/** Value to display */
|
|
18
|
+
value: ReactNode;
|
|
19
|
+
/** Whether this is the total row with border */
|
|
20
|
+
isTotal?: boolean;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Props interface for TokenLabel component */
|
|
24
|
+
interface ITokenLabelProps {
|
|
25
|
+
/** Label text */
|
|
26
|
+
children: string;
|
|
27
|
+
/** Whether this is a total label */
|
|
28
|
+
isTotal?: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Props interface for TokenValue component */
|
|
32
|
+
interface ITokenValueProps {
|
|
33
|
+
/** Value content */
|
|
34
|
+
children: ReactNode;
|
|
35
|
+
/** Color variant for the value */
|
|
36
|
+
variant: "input" | "cachedInput" | "output" | "total";
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Token row component with consistent flex layout */
|
|
40
|
+
const TokenRow = ({ label, value, isTotal = false }: ITokenRowProps) => (
|
|
41
|
+
<div
|
|
42
|
+
style={{
|
|
43
|
+
display: "flex",
|
|
44
|
+
justifyContent: "space-between",
|
|
45
|
+
alignItems: "center",
|
|
46
|
+
...(isTotal && {
|
|
47
|
+
paddingTop: "8px",
|
|
48
|
+
borderTop: `1px solid ${COLORS.GRAY_BORDER_LIGHT}`,
|
|
49
|
+
}),
|
|
50
|
+
}}
|
|
51
|
+
>
|
|
52
|
+
<TokenLabel isTotal={isTotal}>{label}</TokenLabel>
|
|
53
|
+
{value}
|
|
54
|
+
</div>
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
/** Token label component with consistent styling */
|
|
58
|
+
const TokenLabel = ({ children, isTotal = false }: ITokenLabelProps) => (
|
|
59
|
+
<span
|
|
60
|
+
style={{
|
|
61
|
+
color: isTotal ? COLORS.GRAY_TEXT_DARK : COLORS.GRAY_TEXT_MEDIUM,
|
|
62
|
+
fontWeight: isTotal ? "600" : "500",
|
|
63
|
+
}}
|
|
64
|
+
>
|
|
65
|
+
{children}
|
|
66
|
+
</span>
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
/** Token value component with variant-based styling */
|
|
70
|
+
const TokenValue = ({ children, variant }: ITokenValueProps) => {
|
|
71
|
+
const getVariantStyles = () => {
|
|
72
|
+
switch (variant) {
|
|
73
|
+
case "input":
|
|
74
|
+
return { color: COLORS.TOKEN_INPUT, fontWeight: "600" };
|
|
75
|
+
case "cachedInput":
|
|
76
|
+
return {
|
|
77
|
+
color: COLORS.GRAY_TEXT_MEDIUM,
|
|
78
|
+
fontWeight: "400",
|
|
79
|
+
fontSize: "0.875rem",
|
|
80
|
+
};
|
|
81
|
+
case "output":
|
|
82
|
+
return { color: COLORS.TOKEN_OUTPUT, fontWeight: "600" };
|
|
83
|
+
case "total":
|
|
84
|
+
return {
|
|
85
|
+
color: COLORS.TOKEN_TOTAL,
|
|
86
|
+
fontWeight: "700",
|
|
87
|
+
fontSize: "1.125rem",
|
|
88
|
+
};
|
|
89
|
+
default:
|
|
90
|
+
variant satisfies never;
|
|
91
|
+
return {};
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
return <span style={getVariantStyles()}>{children}</span>;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Token usage card component displaying input, output, and total token counts
|
|
100
|
+
*
|
|
101
|
+
* @param props - Component props
|
|
102
|
+
* @returns JSX element representing the token usage card
|
|
103
|
+
*/
|
|
104
|
+
export const AutoBeTokenUsage = ({ tokenUsage }: ITokenUsageCardProps) => {
|
|
105
|
+
return (
|
|
106
|
+
<>
|
|
107
|
+
<div
|
|
108
|
+
style={{
|
|
109
|
+
display: "flex",
|
|
110
|
+
flexDirection: "column",
|
|
111
|
+
gap: "8px",
|
|
112
|
+
}}
|
|
113
|
+
>
|
|
114
|
+
<TokenRow
|
|
115
|
+
label="Input:"
|
|
116
|
+
value={
|
|
117
|
+
<TokenValue variant="input">
|
|
118
|
+
{toCompactNumberFormat(tokenUsage?.aggregate.input.total ?? 0)}
|
|
119
|
+
</TokenValue>
|
|
120
|
+
}
|
|
121
|
+
/>
|
|
122
|
+
<TokenRow
|
|
123
|
+
label="Cached Input:"
|
|
124
|
+
value={
|
|
125
|
+
<TokenValue variant="cachedInput">
|
|
126
|
+
{toCompactNumberFormat(tokenUsage?.aggregate.input.cached ?? 0)}
|
|
127
|
+
</TokenValue>
|
|
128
|
+
}
|
|
129
|
+
/>
|
|
130
|
+
<TokenRow
|
|
131
|
+
label="Output:"
|
|
132
|
+
value={
|
|
133
|
+
<TokenValue variant="output">
|
|
134
|
+
{toCompactNumberFormat(tokenUsage?.aggregate.output.total ?? 0)}
|
|
135
|
+
</TokenValue>
|
|
136
|
+
}
|
|
137
|
+
/>
|
|
138
|
+
<TokenRow
|
|
139
|
+
label="Total:"
|
|
140
|
+
value={
|
|
141
|
+
<TokenValue variant="total">
|
|
142
|
+
{toCompactNumberFormat(tokenUsage?.aggregate.total ?? 0)}
|
|
143
|
+
</TokenValue>
|
|
144
|
+
}
|
|
145
|
+
isTotal
|
|
146
|
+
/>
|
|
147
|
+
</div>
|
|
148
|
+
</>
|
|
149
|
+
);
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
export default AutoBeTokenUsage;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { ReactNode, useState } from "react";
|
|
2
|
+
|
|
3
|
+
import { COLORS } from "../constant/color";
|
|
4
|
+
|
|
5
|
+
/** Props interface for Collapsible component */
|
|
6
|
+
interface ICollapsibleProps {
|
|
7
|
+
/** Title to display in the header */
|
|
8
|
+
title: string;
|
|
9
|
+
/** Content to be collapsed/expanded */
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
/** Initial collapsed state */
|
|
12
|
+
defaultCollapsed?: boolean;
|
|
13
|
+
/** Whether to show animation */
|
|
14
|
+
animated?: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Reusable collapsible component with toggle functionality */
|
|
18
|
+
export const Collapsible = ({
|
|
19
|
+
title,
|
|
20
|
+
children,
|
|
21
|
+
defaultCollapsed = false,
|
|
22
|
+
animated = true,
|
|
23
|
+
}: ICollapsibleProps) => {
|
|
24
|
+
const [isCollapsed, setIsCollapsed] = useState(defaultCollapsed);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<div>
|
|
28
|
+
<div
|
|
29
|
+
style={{
|
|
30
|
+
display: "flex",
|
|
31
|
+
alignItems: "center",
|
|
32
|
+
marginBottom: isCollapsed ? "0" : "12px",
|
|
33
|
+
}}
|
|
34
|
+
>
|
|
35
|
+
<button
|
|
36
|
+
onClick={() => setIsCollapsed(!isCollapsed)}
|
|
37
|
+
style={{
|
|
38
|
+
background: "none",
|
|
39
|
+
border: "none",
|
|
40
|
+
cursor: "pointer",
|
|
41
|
+
padding: "4px",
|
|
42
|
+
borderRadius: "4px",
|
|
43
|
+
display: "flex",
|
|
44
|
+
alignItems: "center",
|
|
45
|
+
justifyContent: "center",
|
|
46
|
+
transition: animated ? "background-color 0.2s" : "none",
|
|
47
|
+
color: COLORS.GRAY_TEXT_MEDIUM,
|
|
48
|
+
marginRight: "8px",
|
|
49
|
+
}}
|
|
50
|
+
onMouseEnter={(e) => {
|
|
51
|
+
e.currentTarget.style.backgroundColor = COLORS.GRAY_BORDER_LIGHT;
|
|
52
|
+
}}
|
|
53
|
+
onMouseLeave={(e) => {
|
|
54
|
+
e.currentTarget.style.backgroundColor = "transparent";
|
|
55
|
+
}}
|
|
56
|
+
>
|
|
57
|
+
<svg
|
|
58
|
+
width="16"
|
|
59
|
+
height="16"
|
|
60
|
+
viewBox="0 0 24 24"
|
|
61
|
+
fill="currentColor"
|
|
62
|
+
style={{
|
|
63
|
+
transform: isCollapsed ? "rotate(-90deg)" : "rotate(0deg)",
|
|
64
|
+
transition: animated ? "transform 0.2s ease" : "none",
|
|
65
|
+
}}
|
|
66
|
+
>
|
|
67
|
+
<path d="M7.41 8.58L12 13.17l4.59-4.59L18 10l-6 6-6-6 1.41-1.42z" />
|
|
68
|
+
</svg>
|
|
69
|
+
</button>
|
|
70
|
+
<h3
|
|
71
|
+
style={{
|
|
72
|
+
margin: 0,
|
|
73
|
+
fontSize: "1.125rem",
|
|
74
|
+
fontWeight: "600",
|
|
75
|
+
color: COLORS.GRAY_TEXT_DARK,
|
|
76
|
+
}}
|
|
77
|
+
>
|
|
78
|
+
{title}
|
|
79
|
+
</h3>
|
|
80
|
+
</div>
|
|
81
|
+
{!isCollapsed && (
|
|
82
|
+
<div
|
|
83
|
+
style={{
|
|
84
|
+
opacity: isCollapsed ? 0 : 1,
|
|
85
|
+
transition: animated ? "opacity 0.2s ease" : "none",
|
|
86
|
+
}}
|
|
87
|
+
>
|
|
88
|
+
{children}
|
|
89
|
+
</div>
|
|
90
|
+
)}
|
|
91
|
+
</div>
|
|
92
|
+
);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export default Collapsible;
|