Skip to content

FEAT: Converter Panel for GUI!#1471

Open
jbolor21 wants to merge 42 commits intomicrosoft:mainfrom
jbolor21:bjagdagdorj/frontend_converters
Open

FEAT: Converter Panel for GUI!#1471
jbolor21 wants to merge 42 commits intomicrosoft:mainfrom
jbolor21:bjagdagdorj/frontend_converters

Conversation

@jbolor21
Copy link
Copy Markdown
Contributor

@jbolor21 jbolor21 commented Mar 15, 2026

Description

Adding converter panels to the GUI interface! This PR only lets you run ONE converter per turn per type of media (ie you can do an image + text conversion in same turn but not two text conversions in one turn)

  • Created converter panel where you can select converter
  • Each converter shows a description of the converter & its parameters (note only simple parameters are editable with UI)
  • Visual badges for see which converters use an LLM - these LLMs will NOT automatically render a preview but will if you click "preview". The rest will auto show the preview!
  • Converter panel uses tabs to let you select which modality you want converter on and filters list based on your input type

Tests and Documentation

  • Manual testing with the UI
  • Frontend unit tests pass (npx jest) & added new e2e tests for new functionality
  • Added unit tests & ensured all unit tests pass

Images:
(new button is shown):
image

(new panel)
image

(panel dropdown)
image

(once you've selected converter)
image

@jbolor21 jbolor21 marked this pull request as draft March 15, 2026 19:24
Bolor and others added 28 commits March 25, 2026 10:15
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jbolor21 jbolor21 force-pushed the bjagdagdorj/frontend_converters branch from 446c643 to 69d038f Compare March 25, 2026 17:16
@jbolor21 jbolor21 marked this pull request as ready for review March 27, 2026 21:44
@jbolor21 jbolor21 changed the title [DRAFT] Converters for Frontend FEAT: Converter Panel for GUI! Mar 27, 2026
noTargetSelected?: boolean
onConfigureTarget?: () => void
onToggleConverterPanel?: () => void
isConverterPanelOpen?: boolean
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this optional ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The panel itself is optional and managed by ChatWindow. The ChatInputAreaajust renders a toggle button rather than rendering the actual panel, this way when omitted the isConverterPanelOPen defaults to false and the button is just disabled. And then you can use the box as a normal box without the converters too.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if theres a way i should make them non optional or change this design feel free to lmk!

@@ -65,9 +68,19 @@ export default function ChatWindow({
const [loadedConversationId, setLoadedConversationId] = useState<string | null>(null)
const isSending = activeConversationId ? sendingConversations.has(activeConversationId) : Boolean(sendingConversations.size)
const [isPanelOpen, setIsPanelOpen] = useState(false)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: useState(false)

not necessary but if we want to be pedantic

}
}

void loadConverters()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is this ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a way to use async/await - think callbacks must be synchronous in React, aka it requires them to either return nothing or return a cleanup function. If you make it async, it returns a Promise instead of a cleanup function, which would break cleanup mechanism.
Then this inner function is just a workaround. Open to other ways to do this for sure!

}, [selectedConverterType, previewText, paramValues, selectedConverter])

const [panelWidth, setPanelWidth] = useState(320)
const isDragging = useRef(false)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm why are we using useRef here ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

useRef.current will give latest value wo triggering re-renders on every mouse drag! this is for the resize handle to resize the panel

onAttachmentsChange?.(types, data)
}

void buildData()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

buildData() ?

as in remove the void

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the void lets the linting work - can't use "await" inside "useEffect" directly?

}

const ChatInputArea = forwardRef<ChatInputAreaHandle, ChatInputAreaProps>(function ChatInputArea({ onSend, disabled = false, activeTarget, singleTurnLimitReached = false, onNewConversation, operatorLocked = false, crossTargetLocked = false, onUseAsTemplate, attackOperator, noTargetSelected = false, onConfigureTarget }, ref) {
const ChatInputArea = forwardRef<ChatInputAreaHandle, ChatInputAreaProps>(function ChatInputArea({ onSend, disabled = false, activeTarget, singleTurnLimitReached = false, onNewConversation, operatorLocked = false, crossTargetLocked = false, onUseAsTemplate, attackOperator, noTargetSelected = false, onConfigureTarget, onToggleConverterPanel, isConverterPanelOpen = false, onInputChange, onAttachmentsChange, convertedValue, originalValue: _originalValue, onClearConversion, onConvertedValueChange, mediaConversions = [], onClearMediaConversion }, ref) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ik you didn't write this but do you know what this forward ref is doing ? I'm not super familiar with forwardref

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets parent component get direct reference to things inside ChatInputArea - here the parent passes ref to CHatInputArea and then the useImperativeHandle exposes the addAttachment and setText methods

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.

2 participants