Skip to content

Commit

Permalink
playgroundfixess (#1351)
Browse files Browse the repository at this point in the history
- **playground bugfixes, next15**
- **some more bugfixes**
- **perf improvement**
- **format**
- **make build work**

<!-- ELLIPSIS_HIDDEN -->


----

> [!IMPORTANT]
> This pull request introduces various bug fixes, performance
improvements, and refactoring across multiple components and files,
enhancing rendering, state management, and code editing functionalities.
> 
>   - **Components**:
> - Add `SuspendedPostHogPageView` in `PostHogPageView.tsx` to optimize
rendering with `Suspense`.
> - Refactor `ProjectView` in `ProjectView.tsx` to use `JotaiProvider`
and improve state management.
> - Update `TopNavbar.tsx` to handle URL creation and sharing logic more
robustly.
>   - **Atoms and State Management**:
> - Remove `sessionStore` from `atoms.ts` and refactor
`activeFileNameAtomRaw`.
> - Introduce `renderedPromptAtom` in `prompt-preview-content.tsx` for
managing prompt data.
>   - **Code Editor**:
> - Enhance `CodeMirrorViewer` in `code-mirror-viewer.tsx` with improved
linter and TypeScript support.
>   - **API and Project Loading**:
>     - Remove deprecated API proxy in `old.ts`.
> - Update `loadProject` in `loadProject.ts` to handle project loading
more efficiently.
>   - **Dependencies**:
>     - Update `@vercel/kv` and `next` versions in `package.json`.
> 
> <sup>This description was created by </sup>[<img alt="Ellipsis"
src="https://img.shields.io/badge/Ellipsis-blue?color=175173">](https://www.ellipsis.dev?ref=BoundaryML%2Fbaml&utm_source=github&utm_medium=referral)<sup>
for c31227e. It will automatically
update as commits are pushed.</sup>


<!-- ELLIPSIS_HIDDEN -->
  • Loading branch information
aaronvg authored Jan 21, 2025
1 parent d08445f commit 4f1cd19
Show file tree
Hide file tree
Showing 25 changed files with 713 additions and 360 deletions.
14 changes: 12 additions & 2 deletions typescript/fiddle-frontend/app/PostHogPageView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

import { usePathname, useSearchParams } from 'next/navigation'
import { usePostHog } from 'posthog-js/react'
import { useEffect } from 'react'
import { Suspense, useEffect } from 'react'

export default function PostHogPageView(): null {
function PostHogPageView(): null {
const pathname = usePathname()
const searchParams = useSearchParams()
const posthog = usePostHog()
Expand All @@ -24,3 +24,13 @@ export default function PostHogPageView(): null {

return null
}
// Wrap this in Suspense to avoid the `useSearchParams` usage above
// from de-opting the whole app into client-side rendering
// See: https://nextjs.org/docs/messages/deopted-into-client-rendering
export default function SuspendedPostHogPageView() {
return (
<Suspense fallback={null}>
<PostHogPageView />
</Suspense>
)
}
3 changes: 1 addition & 2 deletions typescript/fiddle-frontend/app/[project_id]/_atoms/atoms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { filesAtom } from '@/shared/baml-project-panel/atoms'
// import { ParserDBFunctionTestModel } from "@/lib/exampleProjects"
import { TestState } from '@baml/common'
// import { availableFunctionsAtom, selectedFunctionAtom } from '@baml/playground-common/baml_wasm_web/EventListener'
import { sessionStore } from '@baml/playground-common/baml_wasm_web/JotaiProvider'
// import { projectFilesAtom } from '@baml/playground-common/baml_wasm_web/baseAtoms'
import { atom } from 'jotai'
import { atomWithStorage } from 'jotai/utils'
Expand All @@ -25,7 +24,7 @@ export const currentEditorFilesAtom = atom<EditorFile[]>((get) => {
// sessionStore as any,
// )
export const unsavedChangesAtom = atom<boolean>(false)
const activeFileNameAtomRaw = atomWithStorage<string | null>('active_file', null, sessionStore)
const activeFileNameAtomRaw = atomWithStorage<string | null>('active_file', null)
export const activeFileNameAtom = atom(
(get) => {
const files = get(currentEditorFilesAtom)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,36 @@
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@/components/ui/resizable'
import { useKeybindingOverrides } from '@/hooks/command-s'
import type { BAMLProject } from '@/lib/exampleProjects'
import { CodeMirrorViewer, CustomErrorBoundary, PromptPreview } from '@baml/playground-common'
import { CustomErrorBoundary } from '@baml/playground-common'
import { useAtom, useAtomValue, useSetAtom } from 'jotai'
import { Suspense, useEffect, useRef, useState } from 'react'
import { isMobile } from 'react-device-detect'
import { Editable } from '../../_components/EditableText'
import { JotaiProvider } from '@baml/playground-common'
import {
activeFileNameAtom,
currentEditorFilesAtom,
exploreProjectsOpenAtom,
unsavedChangesAtom,
} from '../_atoms/atoms'

import { EventListener } from '@baml/playground-common/baml_wasm_web/EventListener'
import FileViewer from './Tree/FileViewer'
import { ScrollArea } from '@/components/ui/scroll-area'
import { filesAtom } from '@/shared/baml-project-panel/atoms'
import { runtimeStateAtom, selectedFunctionAtom } from '@/shared/baml-project-panel/playground-panel/atoms'
import { useFeedbackWidget } from '@baml/playground-common/lib/feedback_widget'
import { TopNavbar } from './TopNavbar'
import Image from 'next/image'
import dynamic from 'next/dynamic'
const CodeMirrorViewer = dynamic(() => import('@baml/playground-common').then((mod) => mod.CodeMirrorViewer), {
ssr: false,
})
const PromptPreview = dynamic(() => import('@baml/playground-common').then((mod) => mod.PromptPreview), {
ssr: false,
})
const EventListener = dynamic(() => import('@baml/playground-common').then((mod) => mod.EventListener), {
ssr: false,
})

const ProjectViewImpl = ({ project }: { project: BAMLProject }) => {
useFeedbackWidget()
Expand Down Expand Up @@ -51,29 +61,15 @@ const ProjectViewImpl = ({ project }: { project: BAMLProject }) => {
const projectNameInputRef = useRef(null)
const [description, setDescription] = useState(project.description)
const descriptionInputRef = useRef(null)
const setOpenExplorePanel = useSetAtom(exploreProjectsOpenAtom)
const setSelectedFunction = useSetAtom(selectedFunctionAtom)
const { functions } = useAtomValue(runtimeStateAtom)
const editorFiles = useAtomValue(currentEditorFilesAtom)
const stringifiedEditorFilePaths = JSON.stringify(editorFiles.map((f) => f.path))

useEffect(() => {
const func = functions.find((f) => f.span.file_path === activeFileName)
if (func) {
setSelectedFunction(func.name)
}
}, [stringifiedEditorFilePaths, activeFileName, functions])

useEffect(() => {
console.log('activeFileName', activeFileName)
if (activeFileName) {
}
}, [activeFileName])

return (
// firefox wont apply the background color for some reason so we forcefully set it.
<div className='flex relative flex-row w-full h-full main-panel overflow-x-clip overflow-y-clip'>
<EventListener>
<CustomErrorBoundary message='Error loading project'>
<EventListener>
{/* noop for now -- we dont need to nest all the other components in the EventListener since we use jotaiprovider store and we dont want to rerender needlessly */}
<div></div>
</EventListener>
{isMobile && (
<div className='absolute bottom-0 left-0 right-0 font-semibold border-t-[1px] w-full h-[100px] z-50 text-center p-8'>
Visit PromptFiddle on Desktop to get the best experience
Expand Down Expand Up @@ -156,11 +152,29 @@ const ProjectViewImpl = ({ project }: { project: BAMLProject }) => {
</div>
</ResizablePanel>
</ResizablePanelGroup>
</EventListener>
<FunctionSelectorProvider />
</CustomErrorBoundary>
</div>
)
}

export const FunctionSelectorProvider = () => {
const activeFileName = useAtomValue(activeFileNameAtom)

const { functions } = useAtomValue(runtimeStateAtom)
const editorFiles = useAtomValue(currentEditorFilesAtom)
const stringifiedEditorFilePaths = JSON.stringify(editorFiles.map((f) => f.path))
const setSelectedFunction = useSetAtom(selectedFunctionAtom)

useEffect(() => {
const func = functions.find((f) => f.span.file_path === activeFileName)
if (func) {
setSelectedFunction(func.name)
}
}, [stringifiedEditorFilePaths, activeFileName, functions])
return null
}

export const ProjectSidebar = () => {
return (
<ResizablePanel defaultSize={16} className=' h-full dark:bg-[#020309] bg-muted'>
Expand Down Expand Up @@ -188,7 +202,9 @@ export const ProjectSidebar = () => {
export const ProjectView = ({ project }: { project: BAMLProject }) => {
return (
<>
<ProjectViewImpl project={project} />
<JotaiProvider>
<ProjectViewImpl project={project} />
</JotaiProvider>
</>
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
'use client'
/* eslint-disable @typescript-eslint/no-misused-promises */

import { Badge } from '@/components/ui/badge'
import { Button } from '@/components/ui/button'
import type { BAMLProject } from '@/lib/exampleProjects'
Expand All @@ -7,7 +9,7 @@ import Image from 'next/image'
import Link from 'next/link'
import { Editable } from '../../_components/EditableText'
import { GithubStars } from './GithubStars'
import { createUrl } from '@/app/actions'
import { createUrl, test } from '@/app/actions'
import { unsavedChangesAtom } from '../_atoms/atoms'
import { useAtom } from 'jotai'
import { useAtomValue } from 'jotai'
Expand All @@ -17,6 +19,7 @@ import { useState } from 'react'
import posthog from 'posthog-js'
import { toast } from '@/hooks/use-toast'
import { SiDiscord } from 'react-icons/si'
import { Loader } from '@/shared/baml-project-panel/playground-panel/prompt-preview/components'

const ShareButton = ({ project, projectName }: { project: BAMLProject; projectName: string }) => {
const [loading, setLoading] = useState(false)
Expand All @@ -27,27 +30,28 @@ const ShareButton = ({ project, projectName }: { project: BAMLProject; projectNa
return (
<Button
variant={'default'}
className='gap-x-2 py-1 h-full whitespace-nowrap bg-transparent text-secondary-foreground hover:bg-purple-600 w-fit'
className='gap-x-2 py-1 h-full whitespace-nowrap bg-transparent text-secondary-foreground hover:bg-purple-600 w-fit disabled:opacity-50'
disabled={loading}
onClick={async () => {
setLoading(true)
try {
let urlId = pathname?.split('/')[1]
if (!urlId) {
urlId = await createUrl({
...project,
name: projectName,
files: editorFiles,
// TODO: @hellovai use runTestOutput
testRunOutput: undefined,
})
// if (!urlId || urlId === 'new-project') {
// console.log('creating url')
urlId = await createUrl({
...project,
name: projectName,
files: editorFiles,
// TODO: @hellovai use runTestOutput
testRunOutput: undefined,
})

posthog.capture('share_url', { id: urlId })
posthog.capture('share_url', { id: urlId })

const newUrl = `${window.location.origin}/${urlId}`
window.history.replaceState({ ...window.history.state, as: newUrl, url: newUrl }, '', newUrl)
setUnsavedChanges(false)
}
const newUrl = `${window.location.origin}/${urlId}`
window.history.replaceState({ ...window.history.state, as: newUrl, url: newUrl }, '', newUrl)
setUnsavedChanges(false)
// }

navigator.clipboard.writeText(`${window.location.origin}/${urlId}`)

Expand All @@ -69,6 +73,7 @@ const ShareButton = ({ project, projectName }: { project: BAMLProject; projectNa
>
{unsavedChanges ? <GitForkIcon size={14} /> : <LinkIcon size={14} />}
<span>{unsavedChanges ? 'Fork & Share' : 'Share'}</span>
{loading && <Loader />}
</Button>
)
}
Expand All @@ -90,10 +95,10 @@ export const TopNavbar = ({
}: ProjectHeaderProps) => {
return (
<div className='flex flex-row items-center gap-x-12 border-b-[0px] min-h-[55px]'>
<div className='flex flex-col items-center py-1 h-full whitespace-nowrap lg:pr-12 tour-title'>
<div className='flex flex-col items-center py-1 h-full whitespace-nowrap lg:pr-4 tour-title w-[200px] '>
<Editable text={projectName} placeholder='Write a task name' type='input' childRef={projectNameInputRef}>
<input
className='px-2 text-lg border-none text-foreground'
className='px-1 text-lg border-none text-foreground w-[140px]'
type='text'
ref={projectNameInputRef}
name='task'
Expand Down
48 changes: 26 additions & 22 deletions typescript/fiddle-frontend/app/[project_id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,37 @@ import type { BAMLProject } from '@/lib/exampleProjects'
import { loadProject } from '@/lib/loadProject'
import type { Metadata, ResolvingMetadata } from 'next'
import dynamic from 'next/dynamic'
const ProjectView = dynamic(() => import('./_components/ProjectView'), { ssr: false })
// const ProjectView = dynamic(() => import('./_components/ProjectView'), { ssr: true })
import ProjectView from './_components/ProjectView'

type Props = {
params: { project_id: string }
searchParams: { [key: string]: string | string[] | undefined }
}
export async function generateMetadata({ params, searchParams }: Props, parent: ResolvingMetadata): Promise<Metadata> {
type Params = Promise<{ project_id: string }>
type SearchParams = Promise<{ [key: string]: string | string[] | undefined }>

export async function generateMetadata(
props: {
params: Params
searchParams: SearchParams
},
parent: ResolvingMetadata,
): Promise<Metadata> {
// read route params
const project = await loadProject({ project_id: params.project_id })
return {
title: `${project.name} — Prompt Fiddle`,
description: project.description,
try {
const project = await loadProject(Promise.resolve(props.params))
return {
title: `${project.name} — Prompt Fiddle`,
description: project.description,
}
} catch (e) {
console.log('Error generating metadata', e)
return {
title: 'Prompt Fiddle',
description: 'An LLM prompt playground for structured prompting',
}
}
}

type SearchParams = {
id: string
}

export default async function Home({
searchParams,
params,
}: {
searchParams: SearchParams
params: { project_id: string }
}) {
const data: BAMLProject = await loadProject(params)
export default async function Home({ searchParams, params }: { searchParams: SearchParams; params: Params }) {
const data: BAMLProject = await loadProject(Promise.resolve(params))
// console.log(data)
return (
<main className='flex flex-col justify-between items-center min-h-screen font-sans'>
Expand Down
23 changes: 17 additions & 6 deletions typescript/fiddle-frontend/app/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,30 @@ export type EditorFile = {
content: string
}

export async function test() {
await new Promise((resolve) => setTimeout(resolve, 1000))
console.log('test')
return 'test'
}

export async function createUrl(project: BAMLProject): Promise<string> {
// Replace spaces, slashes, and other non-alphanumeric characters with dashes
const projectName = project.name
const safeProjectName = projectName.replace(/[^a-zA-Z0-9]/g, '-')
const urlId = `${safeProjectName}-${nanoid(5)}`
console.log(project)
const urlResponse = await kv.set(urlId, project, {
nx: true,
})
if (!urlResponse) {
console.log('Created urlId', urlId)
try {
const urlResponse = await kv.set(urlId, project, {
nx: true,
})
if (!urlResponse) {
throw new Error('Failed to create URL')
}
return urlId
} catch (e) {
console.log('Error creating url', e)
throw new Error('Failed to create URL')
}
return urlId
}

export async function updateUrl(urlId: string, editorFiles: EditorFile[]): Promise<void> {
Expand Down
25 changes: 10 additions & 15 deletions typescript/fiddle-frontend/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
import { Toaster } from '@/components/ui/toaster'
import { JotaiProvider } from '@baml/playground-common'
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import './globals.css'
import { Toaster } from '@/components/ui/toaster'
import JotaiProvider from '@baml/playground-common/baml_wasm_web/JotaiProvider'
import dynamic from 'next/dynamic'
import { Suspense } from 'react'
import { BrowseSheet } from './_components/BrowseSheet'
import { ErrorBoundary } from 'react-error-boundary'
import { PHProvider, RB2BElement } from './_components/PosthogProvider'
import { ThemeProvider } from './_components/ThemeProvider'
import { ErrorBoundary } from 'react-error-boundary'

const PostHogPageView = dynamic(() => import('./PostHogPageView'), {
ssr: false,
})
import './globals.css'
import PostHogPageView from './PostHogPageView'

const inter = Inter({ subsets: ['latin'] })

Expand All @@ -35,13 +30,13 @@ export default function RootLayout({
<PostHogPageView />
</ErrorBoundary>
<ThemeProvider attribute='class' defaultTheme='dark' enableSystem={false} disableTransitionOnChange={true}>
<JotaiProvider>
<Suspense fallback={<div>Loading...</div>}>{children}</Suspense>
{/* <div className="fixed left-0 bottom-1/2 w-[12%] px-1 items-center justify-center flex">
{/* <JotaiProvider> */}
<Suspense fallback={<div>Loading...</div>}>{children}</Suspense>
{/* <div className="fixed left-0 bottom-1/2 w-[12%] px-1 items-center justify-center flex">
<BrowseSheet />
</div> */}
{/* <PromptPreview /> */}
</JotaiProvider>
{/* <PromptPreview /> */}
{/* </JotaiProvider> */}
<Toaster />
</ThemeProvider>
</body>
Expand Down
Loading

0 comments on commit 4f1cd19

Please sign in to comment.