|
|
@@ -28,7 +28,8 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
|
|
|
onClose,
|
|
|
}) => {
|
|
|
const { apiConfiguration } = useExtensionState()
|
|
|
- const [isExpanded, setIsExpanded] = useState(false)
|
|
|
+ const [isTaskExpanded, setIsTaskExpanded] = useState(true)
|
|
|
+ const [isTextExpanded, setIsTextExpanded] = useState(false)
|
|
|
const [showSeeMore, setShowSeeMore] = useState(false)
|
|
|
const textContainerRef = useRef<HTMLDivElement>(null)
|
|
|
const textRef = useRef<HTMLDivElement>(null)
|
|
|
@@ -68,11 +69,11 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
|
|
|
const { height: windowHeight, width: windowWidth } = useWindowSize()
|
|
|
|
|
|
useEffect(() => {
|
|
|
- if (isExpanded && textContainerRef.current) {
|
|
|
+ if (isTextExpanded && textContainerRef.current) {
|
|
|
const maxHeight = windowHeight * (1 / 2)
|
|
|
textContainerRef.current.style.maxHeight = `${maxHeight}px`
|
|
|
}
|
|
|
- }, [isExpanded, windowHeight])
|
|
|
+ }, [isTextExpanded, windowHeight])
|
|
|
|
|
|
useEffect(() => {
|
|
|
if (textRef.current && textContainerRef.current) {
|
|
|
@@ -83,7 +84,7 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
|
|
|
const isOverflowing = textRef.current.scrollHeight > textContainerHeight
|
|
|
// necessary to show see more button again if user resizes window to expand and then back to collapse
|
|
|
if (!isOverflowing) {
|
|
|
- setIsExpanded(false)
|
|
|
+ setIsTextExpanded(false)
|
|
|
}
|
|
|
setShowSeeMore(isOverflowing)
|
|
|
}
|
|
|
@@ -96,10 +97,10 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
|
|
|
backgroundColor: "var(--vscode-badge-background)",
|
|
|
color: "var(--vscode-badge-foreground)",
|
|
|
borderRadius: "3px",
|
|
|
- padding: "12px",
|
|
|
+ padding: "9px 10px 9px 14px",
|
|
|
display: "flex",
|
|
|
flexDirection: "column",
|
|
|
- gap: "8px",
|
|
|
+ gap: 6,
|
|
|
position: "relative",
|
|
|
zIndex: 1,
|
|
|
}}>
|
|
|
@@ -109,144 +110,191 @@ const TaskHeader: React.FC<TaskHeaderProps> = ({
|
|
|
justifyContent: "space-between",
|
|
|
alignItems: "center",
|
|
|
}}>
|
|
|
- <span style={{ fontWeight: "bold" }}>Task</span>
|
|
|
- <VSCodeButton
|
|
|
- appearance="icon"
|
|
|
- onClick={onClose}
|
|
|
- style={{ marginTop: "-6px", marginRight: "-4px" }}>
|
|
|
- <span className="codicon codicon-close"></span>
|
|
|
- </VSCodeButton>
|
|
|
- </div>
|
|
|
- <div
|
|
|
- ref={textContainerRef}
|
|
|
- style={{
|
|
|
- fontSize: "var(--vscode-font-size)",
|
|
|
- overflowY: isExpanded ? "auto" : "hidden",
|
|
|
- wordBreak: "break-word",
|
|
|
- overflowWrap: "anywhere",
|
|
|
- position: "relative",
|
|
|
- }}>
|
|
|
<div
|
|
|
- ref={textRef}
|
|
|
style={{
|
|
|
- display: "-webkit-box",
|
|
|
- WebkitLineClamp: isExpanded ? "unset" : 3,
|
|
|
- WebkitBoxOrient: "vertical",
|
|
|
- overflow: "hidden",
|
|
|
- whiteSpace: "pre-wrap",
|
|
|
- wordBreak: "break-word",
|
|
|
- overflowWrap: "anywhere",
|
|
|
- }}>
|
|
|
- {task.text}
|
|
|
+ display: "flex",
|
|
|
+ alignItems: "center",
|
|
|
+ cursor: "pointer",
|
|
|
+ marginLeft: -2,
|
|
|
+ userSelect: "none",
|
|
|
+ WebkitUserSelect: "none",
|
|
|
+ MozUserSelect: "none",
|
|
|
+ msUserSelect: "none",
|
|
|
+ flexGrow: 1,
|
|
|
+ minWidth: 0, // This allows the div to shrink below its content size
|
|
|
+ }}
|
|
|
+ onClick={() => setIsTaskExpanded(!isTaskExpanded)}>
|
|
|
+ <div style={{ display: "flex", alignItems: "center", flexShrink: 0 }}>
|
|
|
+ <span className={`codicon codicon-chevron-${isTaskExpanded ? "down" : "right"}`}></span>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ style={{
|
|
|
+ marginLeft: 6,
|
|
|
+ whiteSpace: "nowrap",
|
|
|
+ overflow: "hidden",
|
|
|
+ textOverflow: "ellipsis",
|
|
|
+ flexGrow: 1,
|
|
|
+ minWidth: 0, // This allows the div to shrink below its content size
|
|
|
+ }}>
|
|
|
+ <span style={{ fontWeight: "bold" }}>Task{!isTaskExpanded && ":"}</span>
|
|
|
+ {!isTaskExpanded && <span style={{ marginLeft: 4 }}>{task.text}</span>}
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- {!isExpanded && showSeeMore && (
|
|
|
+ {!isTaskExpanded && (
|
|
|
+ <div
|
|
|
+ style={{
|
|
|
+ marginLeft: 10,
|
|
|
+ backgroundColor: "color-mix(in srgb, var(--vscode-badge-foreground) 70%, transparent)",
|
|
|
+ color: "var(--vscode-badge-background)",
|
|
|
+ padding: "2px 4px",
|
|
|
+ borderRadius: "500px",
|
|
|
+ fontSize: "11px",
|
|
|
+ fontWeight: 500,
|
|
|
+ display: "inline-block",
|
|
|
+ flexShrink: 0,
|
|
|
+ }}>
|
|
|
+ ${totalCost?.toFixed(4)}
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ <VSCodeButton appearance="icon" onClick={onClose} style={{ marginLeft: 10, flexShrink: 0 }}>
|
|
|
+ <span className="codicon codicon-close"></span>
|
|
|
+ </VSCodeButton>
|
|
|
+ </div>
|
|
|
+ {isTaskExpanded && (
|
|
|
+ <>
|
|
|
<div
|
|
|
+ ref={textContainerRef}
|
|
|
style={{
|
|
|
- position: "absolute",
|
|
|
- right: 0,
|
|
|
- bottom: 0,
|
|
|
- display: "flex",
|
|
|
- alignItems: "center",
|
|
|
+ marginTop: -2,
|
|
|
+ fontSize: "var(--vscode-font-size)",
|
|
|
+ overflowY: isTextExpanded ? "auto" : "hidden",
|
|
|
+ wordBreak: "break-word",
|
|
|
+ overflowWrap: "anywhere",
|
|
|
+ position: "relative",
|
|
|
}}>
|
|
|
<div
|
|
|
+ ref={textRef}
|
|
|
style={{
|
|
|
- width: 30,
|
|
|
- height: "1.2em",
|
|
|
- background:
|
|
|
- "linear-gradient(to right, transparent, var(--vscode-badge-background))",
|
|
|
- }}
|
|
|
- />
|
|
|
+ display: "-webkit-box",
|
|
|
+ WebkitLineClamp: isTextExpanded ? "unset" : 3,
|
|
|
+ WebkitBoxOrient: "vertical",
|
|
|
+ overflow: "hidden",
|
|
|
+ whiteSpace: "pre-wrap",
|
|
|
+ wordBreak: "break-word",
|
|
|
+ overflowWrap: "anywhere",
|
|
|
+ }}>
|
|
|
+ {task.text}
|
|
|
+ </div>
|
|
|
+ {!isTextExpanded && showSeeMore && (
|
|
|
+ <div
|
|
|
+ style={{
|
|
|
+ position: "absolute",
|
|
|
+ right: 0,
|
|
|
+ bottom: 0,
|
|
|
+ display: "flex",
|
|
|
+ alignItems: "center",
|
|
|
+ }}>
|
|
|
+ <div
|
|
|
+ style={{
|
|
|
+ width: 30,
|
|
|
+ height: "1.2em",
|
|
|
+ background:
|
|
|
+ "linear-gradient(to right, transparent, var(--vscode-badge-background))",
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ <div
|
|
|
+ style={{
|
|
|
+ cursor: "pointer",
|
|
|
+ color: "var(--vscode-textLink-foreground)",
|
|
|
+ paddingRight: 0,
|
|
|
+ paddingLeft: 3,
|
|
|
+ backgroundColor: "var(--vscode-badge-background)",
|
|
|
+ }}
|
|
|
+ onClick={() => setIsTextExpanded(!isTextExpanded)}>
|
|
|
+ See more
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ </div>
|
|
|
+ {isTextExpanded && showSeeMore && (
|
|
|
<div
|
|
|
style={{
|
|
|
cursor: "pointer",
|
|
|
color: "var(--vscode-textLink-foreground)",
|
|
|
- paddingRight: 0,
|
|
|
- paddingLeft: 3,
|
|
|
- backgroundColor: "var(--vscode-badge-background)",
|
|
|
+ marginLeft: "auto",
|
|
|
+ textAlign: "right",
|
|
|
+ paddingRight: 2,
|
|
|
}}
|
|
|
- onClick={() => setIsExpanded(!isExpanded)}>
|
|
|
- See more
|
|
|
+ onClick={() => setIsTextExpanded(!isTextExpanded)}>
|
|
|
+ See less
|
|
|
</div>
|
|
|
- </div>
|
|
|
- )}
|
|
|
- </div>
|
|
|
- {isExpanded && showSeeMore && (
|
|
|
- <div
|
|
|
- style={{
|
|
|
- cursor: "pointer",
|
|
|
- color: "var(--vscode-textLink-foreground)",
|
|
|
- marginLeft: "auto",
|
|
|
- textAlign: "right",
|
|
|
- paddingRight: 2,
|
|
|
- }}
|
|
|
- onClick={() => setIsExpanded(!isExpanded)}>
|
|
|
- See less
|
|
|
- </div>
|
|
|
- )}
|
|
|
- {task.images && task.images.length > 0 && <Thumbnails images={task.images} />}
|
|
|
- <div style={{ display: "flex", flexDirection: "column", gap: "4px" }}>
|
|
|
- <div
|
|
|
- style={{
|
|
|
- display: "flex",
|
|
|
- justifyContent: "space-between",
|
|
|
- alignItems: "center",
|
|
|
- }}>
|
|
|
- <div style={{ display: "flex", alignItems: "center", gap: "4px", flexWrap: "wrap" }}>
|
|
|
- <span style={{ fontWeight: "bold" }}>Tokens:</span>
|
|
|
- <span style={{ display: "flex", alignItems: "center", gap: "3px" }}>
|
|
|
- <i
|
|
|
- className="codicon codicon-arrow-up"
|
|
|
- style={{ fontSize: "12px", fontWeight: "bold", marginBottom: "-2px" }}
|
|
|
- />
|
|
|
- {tokensIn?.toLocaleString()}
|
|
|
- </span>
|
|
|
- <span style={{ display: "flex", alignItems: "center", gap: "3px" }}>
|
|
|
- <i
|
|
|
- className="codicon codicon-arrow-down"
|
|
|
- style={{ fontSize: "12px", fontWeight: "bold", marginBottom: "-2px" }}
|
|
|
- />
|
|
|
- {tokensOut?.toLocaleString()}
|
|
|
- </span>
|
|
|
- </div>
|
|
|
- {(apiConfiguration?.apiProvider === "openai" || apiConfiguration?.apiProvider === "ollama") && (
|
|
|
- <ExportButton />
|
|
|
)}
|
|
|
- </div>
|
|
|
-
|
|
|
- {(doesModelSupportPromptCache || cacheReads !== undefined || cacheWrites !== undefined) && (
|
|
|
- <div style={{ display: "flex", alignItems: "center", gap: "4px", flexWrap: "wrap" }}>
|
|
|
- <span style={{ fontWeight: "bold" }}>Cache:</span>
|
|
|
- <span style={{ display: "flex", alignItems: "center", gap: "3px" }}>
|
|
|
- <i
|
|
|
- className="codicon codicon-database"
|
|
|
- style={{ fontSize: "12px", fontWeight: "bold", marginBottom: "-1px" }}
|
|
|
- />
|
|
|
- +{(cacheWrites || 0)?.toLocaleString()}
|
|
|
- </span>
|
|
|
- <span style={{ display: "flex", alignItems: "center", gap: "3px" }}>
|
|
|
- <i
|
|
|
- className="codicon codicon-arrow-right"
|
|
|
- style={{ fontSize: "12px", fontWeight: "bold", marginBottom: 0 }}
|
|
|
- />
|
|
|
- {(cacheReads || 0)?.toLocaleString()}
|
|
|
- </span>
|
|
|
- </div>
|
|
|
- )}
|
|
|
- {apiConfiguration?.apiProvider !== "openai" && apiConfiguration?.apiProvider !== "ollama" && (
|
|
|
- <div
|
|
|
- style={{
|
|
|
- display: "flex",
|
|
|
- justifyContent: "space-between",
|
|
|
- alignItems: "center",
|
|
|
- }}>
|
|
|
- <div style={{ display: "flex", alignItems: "center", gap: "4px" }}>
|
|
|
- <span style={{ fontWeight: "bold" }}>API Cost:</span>
|
|
|
- <span>${totalCost?.toFixed(4)}</span>
|
|
|
+ {task.images && task.images.length > 0 && <Thumbnails images={task.images} />}
|
|
|
+ <div style={{ display: "flex", flexDirection: "column", gap: "4px" }}>
|
|
|
+ <div
|
|
|
+ style={{
|
|
|
+ display: "flex",
|
|
|
+ justifyContent: "space-between",
|
|
|
+ alignItems: "center",
|
|
|
+ }}>
|
|
|
+ <div style={{ display: "flex", alignItems: "center", gap: "4px", flexWrap: "wrap" }}>
|
|
|
+ <span style={{ fontWeight: "bold" }}>Tokens:</span>
|
|
|
+ <span style={{ display: "flex", alignItems: "center", gap: "3px" }}>
|
|
|
+ <i
|
|
|
+ className="codicon codicon-arrow-up"
|
|
|
+ style={{ fontSize: "12px", fontWeight: "bold", marginBottom: "-2px" }}
|
|
|
+ />
|
|
|
+ {tokensIn?.toLocaleString()}
|
|
|
+ </span>
|
|
|
+ <span style={{ display: "flex", alignItems: "center", gap: "3px" }}>
|
|
|
+ <i
|
|
|
+ className="codicon codicon-arrow-down"
|
|
|
+ style={{ fontSize: "12px", fontWeight: "bold", marginBottom: "-2px" }}
|
|
|
+ />
|
|
|
+ {tokensOut?.toLocaleString()}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ {(apiConfiguration?.apiProvider === "openai" ||
|
|
|
+ apiConfiguration?.apiProvider === "ollama") && <ExportButton />}
|
|
|
</div>
|
|
|
- <ExportButton />
|
|
|
+
|
|
|
+ {(doesModelSupportPromptCache || cacheReads !== undefined || cacheWrites !== undefined) && (
|
|
|
+ <div style={{ display: "flex", alignItems: "center", gap: "4px", flexWrap: "wrap" }}>
|
|
|
+ <span style={{ fontWeight: "bold" }}>Cache:</span>
|
|
|
+ <span style={{ display: "flex", alignItems: "center", gap: "3px" }}>
|
|
|
+ <i
|
|
|
+ className="codicon codicon-database"
|
|
|
+ style={{ fontSize: "12px", fontWeight: "bold", marginBottom: "-1px" }}
|
|
|
+ />
|
|
|
+ +{(cacheWrites || 0)?.toLocaleString()}
|
|
|
+ </span>
|
|
|
+ <span style={{ display: "flex", alignItems: "center", gap: "3px" }}>
|
|
|
+ <i
|
|
|
+ className="codicon codicon-arrow-right"
|
|
|
+ style={{ fontSize: "12px", fontWeight: "bold", marginBottom: 0 }}
|
|
|
+ />
|
|
|
+ {(cacheReads || 0)?.toLocaleString()}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
+ {apiConfiguration?.apiProvider !== "openai" &&
|
|
|
+ apiConfiguration?.apiProvider !== "ollama" && (
|
|
|
+ <div
|
|
|
+ style={{
|
|
|
+ display: "flex",
|
|
|
+ justifyContent: "space-between",
|
|
|
+ alignItems: "center",
|
|
|
+ }}>
|
|
|
+ <div style={{ display: "flex", alignItems: "center", gap: "4px" }}>
|
|
|
+ <span style={{ fontWeight: "bold" }}>API Cost:</span>
|
|
|
+ <span>${totalCost?.toFixed(4)}</span>
|
|
|
+ </div>
|
|
|
+ <ExportButton />
|
|
|
+ </div>
|
|
|
+ )}
|
|
|
</div>
|
|
|
- )}
|
|
|
- </div>
|
|
|
+ </>
|
|
|
+ )}
|
|
|
</div>
|
|
|
{/* {apiProvider === "kodu" && (
|
|
|
<div
|
|
|
@@ -284,10 +332,12 @@ const ExportButton = () => (
|
|
|
<VSCodeButton
|
|
|
appearance="icon"
|
|
|
onClick={() => vscode.postMessage({ type: "exportCurrentTask" })}
|
|
|
- style={{
|
|
|
- marginBottom: "-2px",
|
|
|
- marginRight: "-2.5px",
|
|
|
- }}>
|
|
|
+ style={
|
|
|
+ {
|
|
|
+ // marginBottom: "-2px",
|
|
|
+ // marginRight: "-2.5px",
|
|
|
+ }
|
|
|
+ }>
|
|
|
<div style={{ fontSize: "10.5px", fontWeight: "bold", opacity: 0.6 }}>EXPORT</div>
|
|
|
</VSCodeButton>
|
|
|
)
|