Skip to content

Commit

Permalink
fix: clean up codemirror panel resizing (#2472)
Browse files Browse the repository at this point in the history
Issue: #2458

Changes:
* Response panel is only displayed when `Body` tab (i.e. Request tab) is
selected, instead of taking screen real estate away from the read-only
schema tabs
* Border between request and response panels is replaced with a
full-width draggable handle
* Related: fixed the existing bugs in
`components/ResizeableVerticalPanels.tsx`
* All codemirror components automatically take the full height of their
container


https://github.com/user-attachments/assets/9594c696-1ddb-4412-bd13-722c73cd7662

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
  • Loading branch information
deniseli and github-actions[bot] authored Aug 21, 2024
1 parent e60586c commit 02b5eeb
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 19 deletions.
12 changes: 10 additions & 2 deletions frontend/src/components/CodeEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,15 @@ export const CodeEditor = ({ initialState, onTextChanged }: { initialState: Init

const state = EditorState.create({
doc: initialState.initialText,
extensions: [commonExtensions, isDarkMode ? atomone : githubLight, json5(), editingExtensions],
extensions: [
...commonExtensions,
isDarkMode ? atomone : githubLight,
json5(),
editingExtensions,
EditorView.theme({
'&': { height: '100%' },
}),
],
})

const view = new EditorView({
Expand All @@ -94,5 +102,5 @@ export const CodeEditor = ({ initialState, onTextChanged }: { initialState: Init
}
}, [initialState, isDarkMode])

return <div ref={editorContainerRef} />
return <div className='h-full' ref={editorContainerRef} />
}
14 changes: 8 additions & 6 deletions frontend/src/components/ResizeableVerticalPanels.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,14 @@ export const ResizableVerticalPanels: React.FC<ResizableVerticalPanelsProps> = (
}

const onDrag = (e: React.MouseEvent<HTMLDivElement>) => {
if (isDragging) {
const newHeight = e.clientY
const maxHeight = window.innerHeight - minBottomPanelHeight
if (newHeight >= minTopPanelHeight && newHeight <= maxHeight) {
setTopPanelHeight(newHeight - 44)
}
if (!isDragging || !containerRef.current) {
return
}
const containerDims = containerRef.current.getBoundingClientRect()
const newHeight = e.clientY - containerDims.top
const maxHeight = containerDims.height - minBottomPanelHeight
if (newHeight >= minTopPanelHeight && newHeight <= maxHeight) {
setTopPanelHeight(newHeight)
}
}

Expand Down
4 changes: 2 additions & 2 deletions frontend/src/features/verbs/VerbFormInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const VerbFormInput = ({
return (
<form onSubmit={handleSubmit} className='rounded-lg'>
<div className='flex rounded-md shadow-sm'>
<span className='inline-flex items-center rounded-l-md border border-r-0 border-gray-300 dark:border-gray-500 px-3 sm:text-sm'>{requestType}</span>
<span className='inline-flex items-center rounded-l-md border border-r-0 border-gray-300 dark:border-gray-500 px-3 ml-4 sm:text-sm'>{requestType}</span>
<input
type='text'
name='request-path'
Expand All @@ -37,7 +37,7 @@ export const VerbFormInput = ({
readOnly={readOnly}
onChange={(event) => setPath(event.target.value)}
/>
<button type='submit' className='bg-indigo-700 text-white ml-2 px-4 py-2 rounded-lg hover:bg-indigo-600 focus:outline-none focus:bg-indigo-600'>
<button type='submit' className='bg-indigo-700 text-white ml-2 mr-4 px-4 py-2 rounded-lg hover:bg-indigo-600 focus:outline-none focus:bg-indigo-600'>
Send
</button>
</div>
Expand Down
25 changes: 16 additions & 9 deletions frontend/src/features/verbs/VerbRequestForm.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useEffect, useState } from 'react'
import { CodeEditor, type InitialState } from '../../components/CodeEditor'
import { ResizableVerticalPanels } from '../../components/ResizeableVerticalPanels'
import { useClient } from '../../hooks/use-client'
import type { Module, Verb } from '../../protos/xyz/block/ftl/v1/console/console_pb'
import { VerbService } from '../../protos/xyz/block/ftl/v1/ftl_connect'
Expand Down Expand Up @@ -101,8 +102,19 @@ export const VerbRequestForm = ({ module, verb }: { module?: Module; verb?: Verb

const bottomText = response ?? error ?? ''

const bodyEditor = <CodeEditor initialState={initialEditorState} onTextChanged={handleEditorTextChanged} />
const bodyPanels =
bottomText === '' ? (
bodyEditor
) : (
<ResizableVerticalPanels
topPanelContent={bodyEditor}
bottomPanelContent={<CodeEditor initialState={{ initialText: bottomText, readonly: true }} onTextChanged={setHeadersText} />}
/>
)

return (
<div className='flex flex-col h-full overflow-hidden pt-4 px-4'>
<div className='flex flex-col h-full overflow-hidden pt-4'>
<VerbFormInput
requestType={requestType(verb)}
initialPath={httpPopulatedRequestPath(module, verb)}
Expand All @@ -112,7 +124,7 @@ export const VerbRequestForm = ({ module, verb }: { module?: Module; verb?: Verb
/>
<div>
<div className='border-b border-gray-200 dark:border-white/10'>
<nav className='-mb-px flex space-x-6' aria-label='Tabs'>
<nav className='-mb-px flex space-x-6 pl-4' aria-label='Tabs'>
{tabs.map((tab) => (
<button
type='button'
Expand All @@ -133,17 +145,12 @@ export const VerbRequestForm = ({ module, verb }: { module?: Module; verb?: Verb
</div>
</div>
<div className='flex-1 overflow-hidden'>
<div className='h-1/2 overflow-y-scroll'>
{activeTabId === 'body' && <CodeEditor initialState={initialEditorState} onTextChanged={handleEditorTextChanged} />}
<div className='h-full overflow-y-scroll'>
{activeTabId === 'body' && bodyPanels}
{activeTabId === 'verbschema' && <CodeEditor initialState={{ initialText: verb?.schema ?? 'what', readonly: true }} />}
{activeTabId === 'jsonschema' && <CodeEditor initialState={{ initialText: verb?.jsonRequestSchema ?? '', readonly: true }} />}
{activeTabId === 'headers' && <CodeEditor initialState={initialHeadersState} onTextChanged={handleHeadersTextChanged} />}
</div>

<div className='border-b border-gray-200 dark:border-white/10' />
<div className='h-1/2 overflow-y-scroll'>
<CodeEditor initialState={{ initialText: bottomText, readonly: true }} onTextChanged={setHeadersText} />
</div>
</div>
</div>
)
Expand Down

0 comments on commit 02b5eeb

Please sign in to comment.