Skip to content

1283 playground UI refactor 2#1604

Merged
neelneelneel merged 3 commits intodevfrom
1283-playground-ui-refactor-2
Jul 29, 2025
Merged

1283 playground UI refactor 2#1604
neelneelneel merged 3 commits intodevfrom
1283-playground-ui-refactor-2

Conversation

@neelneelneel
Copy link
Copy Markdown
Contributor

Description

Changes Made

How to Test

  1. Steps to reproduce/test the behavior
  2. Expected outcomes

Notes

@neelneelneel neelneelneel requested a review from a team as a code owner July 29, 2025 04:42
@neelneelneel neelneelneel linked an issue Jul 29, 2025 that may be closed by this pull request
7 tasks
@github-actions
Copy link
Copy Markdown

@CodiumAI-Agent /describe

@neelneelneel neelneelneel merged commit d03386e into dev Jul 29, 2025
4 checks passed
@neelneelneel neelneelneel deleted the 1283-playground-ui-refactor-2 branch July 29, 2025 04:42
@github-actions
Copy link
Copy Markdown

@CodiumAI-Agent /update_changelog

@github-actions
Copy link
Copy Markdown

@CodiumAI-Agent /review

@QodoAI-Agent
Copy link
Copy Markdown

Title

1283 playground UI refactor 2


User description

Description

Changes Made

How to Test

  1. Steps to reproduce/test the behavior
  2. Expected outcomes

Notes


PR Type

Enhancement


Description

  • Refactor playground pages into reusable components

  • Add file upload and drag-drop support in chat input

  • Implement Tools and Knowledge overlay modals

  • Extract prompt library and options picker components


Diagram Walkthrough

flowchart LR
  NewRoomPage["NewRoomPage"] -- "uses" --> RoomInput["RoomInput"]
  RoomInput -- "onPrompt(files)" --> ChatRoom["ChatRoom.askModel"]
  ChatRoom -- "uploads files" --> Insight["Insight SDK"]
  ChatRoom -- "navigates to" --> RoomPage["RoomPage"]
  NewRoomPage -- "opens" --> ToolsOverlay["ToolsOverlay"]
  NewRoomPage -- "opens" --> KnowledgeOverlay["KnowledgeOverlay"]
Loading

File Walkthrough

Relevant files

@QodoAI-Agent
Copy link
Copy Markdown

Changelog updates: 🔄

2025-07-29 *

  • Added image and file upload support in the playground chat interface
  • Refactored playground UI components and streamlined options/prompt flows

to commit the new content to the CHANGELOG.md file, please type:
'/update_changelog --pr_update_changelog.push_changelog_changes=true'

@github-actions
Copy link
Copy Markdown

@CodiumAI-Agent /improve

@QodoAI-Agent
Copy link
Copy Markdown

PR Reviewer Guide 🔍

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 5 🔵🔵🔵🔵🔵
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Error Handling

The async askModel function lacks a try/catch block; errors during room creation or model query will leave isLoading true and prevent navigation or UI updates.

const askModel = async (prompt: string, files: File[]) => {
	// ignore if loading
	if (isLoading) {
		return;
	}

	// turn the loading screen
	setIsLoading(true);

	// create a new room
	const room = await chat.createRoom(chat.models.selected, prompt);

	// initialize it
	await room.initialize();

	// ask the room
	await room.askModel(prompt, files, options);

	// turn the loading screen off
	setIsLoading(false);

	// go to the new room
	navigate(`/room/${room.roomId}`);
};
Query Injection

The dynamic pixel query interpolates user search and filter values directly into the query string without escaping, which could lead to invalid queries or injection issues.

const getPrompts = usePixel<Prompt[]>(
	`ListPrompt(${
		debouncedSearch
			? `filters=[Filter(PROMPT__TITLE==["${debouncedSearch}"])] ,`
			: ""
	} ${filter ? `metaFilters=[Filter(TAG==["${filter}"])] ,` : ""});`,
	{
Resource Leak

The onSave flow may create a new engine and then unmount before cleanup checks, potentially leaking created engines if isMounted checks occur too late.

if (!isMounted.current) {
	return;
}

// create the engine
const createEngine = await actions.run<
	[
		{
			database_id: string;
			database_name: string;
		},
	]
>(
	`CreateVectorDatabaseEngine ( database=["${newEngineData.name}"], conDetails=[{"NAME":"${newEngineData.name}", "VECTOR_TYPE":"FAISS", "EMBEDDER_ENGINE_ID":"${EMBEDDING_MODEL}","INDEX_CLASSES":"default","CHUNKING_STRATEGY":"ALL","CONTENT_LENGTH":512,"CONTENT_OVERLAP":20,"KEEP_INPUT_OUTPUT":"true","DISTANCE_METHOD":"Squared Euclidean (L2) distance"}] );`,
);

// store the id
newEngineId = createEngine.pixelReturn[0].output.database_id;
const newEngineName =
	createEngine.pixelReturn[0].output.database_name;

// delete if unmounted early
if (!isMounted.current) {
	if (newEngineId) {
		await actions.run<[boolean]>(
			`DeleteEngine(engine=["${newEngineId}"]);`,
		);
	}
	return;
}
// upload files

@QodoAI-Agent
Copy link
Copy Markdown

PR Code Suggestions ✨

CategorySuggestion                                                                                                                                    Impact
Possible issue
Correct URL query string assembly

The query string generation uses concat("&") on the params array, which produces a
malformed comma-separated string with an extra ampersand. Switch to join("&") to
correctly assemble the URL parameters.

packages/playground/src/components/room/RoomApp.tsx [58-60]

 if (params.length > 0) {
-    url += `?${params.concat("&")}`;
+    url += `?${params.join("&")}`;
 }
Suggestion importance[1-10]: 8

__

Why: Using params.concat("&") produces a comma‐separated array string including "&", resulting in malformed query parameters; switching to params.join("&") fixes the URL assembly.

Medium
Restore tool response handling

The tool execution branch is commented out so tool results never render; uncomment
and use the correct arguments structure to update message content.

packages/playground/src/stores/chat/chat.room.ts [605-612]

 } else if (pixelMessage.type === "INPUT_TOOL_EXEC") {
     message.updateType("AGENT");
-// message.updateContent({
-// 	type: "APP",
-// 	name: pixelMessage.toolResponse.name,
-// 	id: pixelMessage.toolResponse.arguments.id,
-// 	map: pixelMessage.toolResponse.arguments.map,
-// });
+    message.updateContent({
+        type: "APP",
+        name: pixelMessage.toolResponse.name,
+        id: pixelMessage.toolResponse.arguments.id,
+        map: pixelMessage.toolResponse.arguments.map,
+    });
Suggestion importance[1-10]: 8

__

Why: Uncommenting message.updateContent for INPUT_TOOL_EXEC fixes the broken tool execution branch and restores critical functionality.

Medium
Reset attachments on submit

After a successful prompt, the attached files remain in state and may be resubmitted
by mistake. Clear the files array when the prompt succeeds to reset attachments.

packages/playground/src/components/room/RoomInput.tsx [154-159]

 if (success) {
-    // clear the input
+    // clear the input and attached files
     setInput("");
+    setFiles([]);
 } else {
     throw new Error(`Error processing chat`);
 }
Suggestion importance[1-10]: 7

__

Why: Clearing the files state after a successful prompt prevents stale attachments from persisting and being accidentally resubmitted.

Medium
General
Prevent newline on send

Pressing Enter currently triggers promptModel but also inserts a newline in the
textarea. Prevent the default event when Enter is pressed without Shift to send, and
allow Shift+Enter for a newline.

packages/playground/src/components/room/RoomInput.tsx [245-249]

 onKeyDown={(e) => {
-    if (e.key === "Enter") {
+    if (e.key === "Enter" && !e.shiftKey) {
+        e.preventDefault();
         promptModel(input);
     }
 }}
Suggestion importance[1-10]: 6

__

Why: Preventing the default in the onKeyDown handler stops unintended newlines when sending with Enter and allows Shift+Enter to insert a newline.

Low
Handle upload errors gracefully

Guard against upload failures by wrapping the upload call in try/catch and default
to an empty array on error to prevent the request from breaking.

packages/playground/src/stores/chat/chat.room.ts [369-370]

-// upload the files
-const uploaded = await this.upload(files);
+let uploaded: Array<{ fileLocation: string }> = [];
+try {
+  uploaded = await this.upload(files);
+} catch {
+  uploaded = [];
+}
 ...
--image=[],
--url=[],
-+${files.length ? `url=${JSON.stringify(uploaded.map((file) => file.fileLocation))},` : "url=[],"}
+url=${files.length ? JSON.stringify(uploaded.map(f => f.fileLocation)) : []},
Suggestion importance[1-10]: 6

__

Why: Wrapping this.upload(files) in try/catch prevents request failures from breaking message sending and provides a safe default, improving robustness.

Low

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Playground UI Refactor

2 participants