Skip to content

Commit

Permalink
Adding better UX for playground (#742)
Browse files Browse the repository at this point in the history
* Better render envvars buttons
* Show docs links in playground
* Use dropdowns to select test cases / functions
* Add jump to file in playground

<img width="755" alt="Screenshot 2024-07-02 at 10 28 19 PM"
src="https://github.com/BoundaryML/baml/assets/2448742/6db4379c-6c9d-402b-9aab-87cd4f872df3">
<img width="1301" alt="Screenshot 2024-07-02 at 10 21 50 PM"
src="https://github.com/BoundaryML/baml/assets/2448742/da278fe6-d91e-447e-a672-29bb83b16c3c">
  • Loading branch information
hellovai authored Jul 3, 2024
1 parent 2755b43 commit 5cb56fd
Show file tree
Hide file tree
Showing 27 changed files with 609 additions and 147 deletions.
11 changes: 9 additions & 2 deletions engine/baml-lib/baml-core/src/ir/repr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ use internal_baml_parser_database::{
ClassWalker, ClientWalker, ConfigurationWalker, EnumValueWalker, EnumWalker, FieldWalker,
FunctionWalker, TemplateStringWalker, VariantWalker,
},
ParserDatabase, PromptAst, RetryPolicyStrategy, ToStringAttributes,
WithStaticRenames,
ParserDatabase, PromptAst, RetryPolicyStrategy, ToStringAttributes, WithStaticRenames,
};

use internal_baml_schema_ast::ast::{self, FieldArity, WithName, WithSpan};
Expand Down Expand Up @@ -1102,6 +1101,14 @@ pub struct TestCase {
}

impl WithRepr<TestCase> for ConfigurationWalker<'_> {
fn attributes(&self, _db: &ParserDatabase) -> NodeAttributes {
NodeAttributes {
meta: IndexMap::new(),
overrides: IndexMap::new(),
span: Some(self.span().clone()),
}
}

fn repr(&self, db: &ParserDatabase) -> Result<TestCase> {
Ok(TestCase {
name: self.name().to_string(),
Expand Down
4 changes: 4 additions & 0 deletions engine/baml-lib/baml-core/src/ir/walker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,10 @@ impl<'a> Walker<'a, (&'a Function, &'a TestCase)> {
&self.item.1.elem
}

pub fn span(&self) -> Option<&crate::Span> {
self.item.1.attributes.span.as_ref()
}

pub fn test_case_params(
&self,
env_values: &HashMap<String, String>,
Expand Down
3 changes: 3 additions & 0 deletions engine/baml-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ pub use internal_baml_jinja::{ChatMessagePart, RenderedPrompt};
#[cfg(feature = "internal")]
pub use runtime_interface::InternalRuntimeInterface;

#[cfg(feature = "internal")]
pub use internal_baml_core as internal_core;

#[cfg(not(feature = "internal"))]
pub(crate) use internal_baml_jinja::{ChatMessagePart, RenderedPrompt};
#[cfg(not(feature = "internal"))]
Expand Down
61 changes: 51 additions & 10 deletions engine/baml-schema-wasm/src/runtime_wasm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,8 @@ pub struct WasmFunction {
pub test_cases: Vec<WasmTestCase>,
#[wasm_bindgen(readonly)]
pub test_snippet: String,
#[wasm_bindgen(readonly)]
pub signature: String,
}

#[wasm_bindgen(getter_with_clone, inspectable)]
Expand All @@ -268,6 +270,31 @@ pub struct WasmSpan {
pub start: usize,
#[wasm_bindgen(readonly)]
pub end: usize,
#[wasm_bindgen(readonly)]
pub start_line: usize,
}

impl From<&baml_runtime::internal_core::internal_baml_diagnostics::Span> for WasmSpan {
fn from(span: &baml_runtime::internal_core::internal_baml_diagnostics::Span) -> Self {
let (start, end) = span.line_and_column();
WasmSpan {
file_path: span.file.path().to_string(),
start: span.start,
end: span.end,
start_line: start.0,
}
}
}

impl Default for WasmSpan {
fn default() -> Self {
WasmSpan {
file_path: "".to_string(),
start: 0,
end: 0,
start_line: 0,
}
}
}

#[wasm_bindgen(getter_with_clone, inspectable)]
Expand All @@ -279,6 +306,8 @@ pub struct WasmTestCase {
pub inputs: Vec<WasmParam>,
#[wasm_bindgen(readonly)]
pub error: Option<String>,
#[wasm_bindgen(readonly)]
pub span: WasmSpan,
}

#[wasm_bindgen(getter_with_clone, inspectable)]
Expand Down Expand Up @@ -743,21 +772,27 @@ impl WasmRuntime {
);

let wasm_span = match f.span() {
Some(span) => WasmSpan {
file_path: span.file.path().to_string(),
start: span.start,
end: span.end,
},
None => WasmSpan {
file_path: "".to_string(),
start: 0,
end: 0,
},
Some(span) => span.into(),
None => WasmSpan::default(),
};

WasmFunction {
name: f.name().to_string(),
span: wasm_span,
signature: {
let inputs = f
.inputs()
.right()
.map(|func_params| {
func_params
.iter()
.map(|(k, t)| format!("{}: {}", k, t))
.collect::<Vec<_>>()
.join(", ")
})
.unwrap_or_default();
format!("({}) -> {}", inputs, f.output().to_string())
},
test_snippet: snippet,
test_cases: f
.walk_tests()
Expand Down Expand Up @@ -812,10 +847,16 @@ impl WasmRuntime {
}
});

let wasm_span = match tc.span() {
Some(span) => span.into(),
None => WasmSpan::default(),
};

WasmTestCase {
name: tc.test_case().name.clone(),
inputs: params,
error,
span: wasm_span,
}
})
.collect(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
CustomErrorBoundary,
EventListener,
FunctionPanel,
FunctionSelector,
//useSelections,
} from '@baml/playground-common'
import { updateFileAtom } from '@baml/playground-common/baml_wasm_web/EventListener'
Expand Down Expand Up @@ -42,10 +41,11 @@ import { CodeMirrorEditor } from './CodeMirrorEditor'

import { GithubStars } from './GithubStars'
import { InitialTour, PostTestRunTour } from './Tour'
import SettingsDialog, { ShowSettingsButton, showSettingsAtom } from '@baml/playground-common/shared/SettingsDialog'
import SettingsDialog, { ShowSettingsButton } from '@baml/playground-common/shared/SettingsDialog'

import FileViewer from './Tree/FileViewer'
import { AppStateProvider } from '@baml/playground-common/shared/AppStateContext' // Import the AppStateProvider
import { ViewSelector } from '@baml/playground-common/shared/Selectors'

const ProjectViewImpl = ({ project }: { project: BAMLProject }) => {
const setEditorFiles = useSetAtom(updateFileAtom)
Expand Down Expand Up @@ -220,10 +220,7 @@ const ProjectViewImpl = ({ project }: { project: BAMLProject }) => {
}}
className='flex flex-row h-full overflow-clip'
>
<ResizablePanelGroup
className='min-h-[200px] w-full rounded-lg border overflow-clip'
direction='horizontal'
>
<ResizablePanelGroup className='min-h-[200px] w-full rounded-lg overflow-clip' direction='horizontal'>
<ResizablePanel defaultSize={50}>
<div className='flex flex-col w-full py-1 pl-2 text-xs border-none items-left h-fit whitespace-nowrap'>
<Editable
Expand All @@ -247,7 +244,7 @@ const ProjectViewImpl = ({ project }: { project: BAMLProject }) => {
<CodeMirrorEditor project={project} />
</div>
</ResizablePanel>
<ResizableHandle className='bg-vscode-contrastActiveBorder' />
<ResizableHandle className='bg-vscode-tab-activeBackground' />
{!isMobile && (
<ResizablePanel defaultSize={50} className='tour-playground'>
<div className='flex flex-row h-full bg-vscode-panel-background'>
Expand Down Expand Up @@ -337,13 +334,10 @@ const PlaygroundView = () => {
<SettingsDialog />
<div className='relative flex flex-col w-full gap-2 pr-0'>
<div className='relative flex flex-row gap-2'>
<FunctionSelector />
<div className='relative flex flex-row items-center justify-end gap-2 pr-1 grow'>
<ShowSettingsButton
buttonClassName='h-8 px-2 bg-black/70 hover:bg-white text-white hover:text-black'
iconClassName='h-5'
/>
<div className='flex flex-row items-start justify-start gap-2 pr-1 grow'>
<ViewSelector />
</div>
<div className='relative flex flex-row items-center justify-end gap-2 pr-1 grow'></div>
</div>
{/* <Separator className="bg-vscode-textSeparator-foreground" /> */}
<FunctionPanel />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,18 +137,18 @@ const FileViewer = () => {
)

return (
<div className='flex flex-col w-full h-full overflow-x-clip'>
<div className='pl-2 folderFileActions'>{createFileFolder}</div>
<div className='flex flex-col w-full h-full overflow-x-clip pl-2'>
<div className='folderFileActions'>{createFileFolder}</div>
{/* <input
type="text"
placeholder="Search..."
className="search-input"
value={term}
onChange={(e) => setTerm(e.target.value)}
/> */}
<div ref={ref} className='flex flex-col h-full '>
<div ref={ref} className='flex flex-col h-full'>
<Tree
className='truncate '
className='truncate'
ref={treeRef}
openByDefault={false}
// initialOpenState={{ baml_src: true }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,17 @@ const Node = ({ node, style, dragHandle, tree }: NodeRendererProps<any>) => {
style={style}
ref={dragHandle}
>
<div className='flex flex-row items-center w-full pl-2 gap-x-1' onClick={() => node.isInternal && node.toggle()}>
<div className='flex flex-row items-center w-full justify-start' onClick={() => node.isInternal && node.toggle()}>
{node.isLeaf ? (
<>
<span className='arrow'></span>
<span className=''></span>
{renderIcon(node.id)}
</>
) : (
<>
<span className='arrow'>{node.isOpen ? <ChevronDown size={12} /> : <ChevronRight size={12} />}</span>
<span className='w-fit'>
{node.isOpen ? <ChevronDown className='w-3 h-fit' /> : <ChevronRight size={12} />}
</span>
{/* <span className="file-folder-icon">
<Folder color="#f6cf60" size={16} />
</span> */}
Expand Down Expand Up @@ -137,7 +139,12 @@ const Node = ({ node, style, dragHandle, tree }: NodeRendererProps<any>) => {
autoFocus
/>
) : (
<span className={clsx(fileHasErrors ? 'text-red-500' : node.state.isSelected ? 'text-white' : '')}>
<span
className={clsx(
fileHasErrors ? 'text-red-500' : node.state.isSelected ? 'text-white' : '',
'text-xs pl-1',
)}
>
{node.data.name}
</span>
)}
Expand All @@ -146,7 +153,7 @@ const Node = ({ node, style, dragHandle, tree }: NodeRendererProps<any>) => {

{node.id !== 'baml_src' && (
<div className='absolute top-0 right-0 hidden rounded-md group-hover:flex bg-zinc-800'>
<div className='flex flex-row items-center gap-x-1 '>
<div className='flex flex-row items-center'>
<button
className='p-1 hover:opacity-100 opacity-70'
onClick={(e) => {
Expand Down
1 change: 1 addition & 0 deletions typescript/playground-common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
"@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-toast": "^1.1.5",
"@radix-ui/react-toggle": "^1.0.3",
"@radix-ui/react-toggle-group": "^1.1.0",
"@radix-ui/react-tooltip": "^1.0.7",
"@rjsf/core": "^5.15.0",
"@rjsf/utils": "^5.15.0",
Expand Down
90 changes: 90 additions & 0 deletions typescript/playground-common/src/components/ui/breadcrumb.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import * as React from 'react'
import { ChevronRightIcon, DotsHorizontalIcon } from '@radix-ui/react-icons'
import { Slot } from '@radix-ui/react-slot'

import { cn } from '@/lib/utils'

const Breadcrumb = React.forwardRef<
HTMLElement,
React.ComponentPropsWithoutRef<'nav'> & {
separator?: React.ReactNode
}
>(({ ...props }, ref) => <nav ref={ref} aria-label='breadcrumb' {...props} />)
Breadcrumb.displayName = 'Breadcrumb'

const BreadcrumbList = React.forwardRef<HTMLOListElement, React.ComponentPropsWithoutRef<'ol'>>(
({ className, ...props }, ref) => (
<ol
ref={ref}
className={cn(
'flex flex-wrap items-center gap-1.5 break-words text-sm text-muted-foreground sm:gap-2.5',
className,
)}
{...props}
/>
),
)
BreadcrumbList.displayName = 'BreadcrumbList'

const BreadcrumbItem = React.forwardRef<HTMLLIElement, React.ComponentPropsWithoutRef<'li'>>(
({ className, ...props }, ref) => (
<li ref={ref} className={cn('inline-flex items-center gap-1.5', className)} {...props} />
),
)
BreadcrumbItem.displayName = 'BreadcrumbItem'

const BreadcrumbLink = React.forwardRef<
HTMLAnchorElement,
React.ComponentPropsWithoutRef<'a'> & {
asChild?: boolean
}
>(({ asChild, className, ...props }, ref) => {
const Comp = asChild ? Slot : 'a'

return <Comp ref={ref} className={cn('transition-colors hover:text-foreground', className)} {...props} />
})
BreadcrumbLink.displayName = 'BreadcrumbLink'

const BreadcrumbPage = React.forwardRef<HTMLSpanElement, React.ComponentPropsWithoutRef<'span'>>(
({ className, ...props }, ref) => (
<span
ref={ref}
role='link'
aria-disabled='true'
aria-current='page'
className={cn('font-normal text-foreground', className)}
{...props}
/>
),
)
BreadcrumbPage.displayName = 'BreadcrumbPage'

const BreadcrumbSeparator = ({ children, className, ...props }: React.ComponentProps<'li'>) => (
<li role='presentation' aria-hidden='true' className={cn('[&>svg]:size-3.5', className)} {...props}>
{children ?? <ChevronRightIcon />}
</li>
)
BreadcrumbSeparator.displayName = 'BreadcrumbSeparator'

const BreadcrumbEllipsis = ({ className, ...props }: React.ComponentProps<'span'>) => (
<span
role='presentation'
aria-hidden='true'
className={cn('flex h-9 w-9 items-center justify-center', className)}
{...props}
>
<DotsHorizontalIcon className='h-4 w-4' />
<span className='sr-only'>More</span>
</span>
)
BreadcrumbEllipsis.displayName = 'BreadcrumbElipssis'

export {
Breadcrumb,
BreadcrumbList,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbPage,
BreadcrumbSeparator,
BreadcrumbEllipsis,
}
Loading

0 comments on commit 5cb56fd

Please sign in to comment.