Skip to content

Commit 8e8cdc3

Browse files
authored
Persist tests and functions across code errors (#1644)
With this change, if a user changes their baml_src in a way that prevents a runtime from being generated, we use the previous good runtime state to populate the list of functions/tests in the test panel, rather than just deleting the list. The list with the previous names is greyed out and has mouse interactions blocked, to indicate that it is not actively usable. <!-- ELLIPSIS_HIDDEN --> ---- > [!IMPORTANT] > Retain and display last valid runtime state in greyed-out form when new runtime cannot be generated, updating `runtimeAtom` and UI components accordingly. > > - **Behavior**: > - Retain last valid runtime state in `runtimeAtom` when new runtime cannot be generated. > - Display previous functions/tests in greyed-out state in the test panel. > - **Atoms**: > - Update `runtimeAtom` in `atoms.ts` to include `lastValidRt`. > - Modify `runtimeStateAtom` in `playground-panel/atoms.ts` to use `lastValidRt` when `rt` is undefined. > - **UI**: > - Add `functionsAreStaleAtom` in `side-bar/index.tsx` to determine if functions are stale. > - Apply `pointer-events-none opacity-50` to sidebar when functions are stale. > > <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 889d9df. It will automatically update as commits are pushed.</sup> <!-- ELLIPSIS_HIDDEN -->
1 parent c96fdb4 commit 8e8cdc3

3 files changed

Lines changed: 41 additions & 13 deletions

File tree

typescript/playground-common/src/shared/baml-project-panel/atoms.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { vscodeLocalStorageStore } from './Jotai'
77
import { orchIndexAtom } from './playground-panel/atoms-orch-graph'
88
import { vscode } from './vscode'
99
import { bamlConfig } from '../../baml_wasm_web/bamlConfig'
10+
import { WasmDiagnosticError, WasmRuntime } from '@gloo-ai/baml-schema-wasm-web/baml_schema_build'
1011

1112
const wasmAtomAsync = atom(async () => {
1213
const wasm = await import('@gloo-ai/baml-schema-wasm-web/baml_schema_build')
@@ -77,25 +78,39 @@ export const ctxAtom = atom((get) => {
7778
return context
7879
})
7980

80-
export const runtimeAtom = atom((get) => {
81+
export const runtimeAtom = atom<{
82+
rt: WasmRuntime | undefined
83+
diags: WasmDiagnosticError | undefined
84+
lastValidRt: WasmRuntime | undefined
85+
}>((get) => {
8186
try {
8287
const wasm = get(wasmAtom)
8388
const project = get(projectAtom)
8489
const envVars = get(envVarsAtom)
8590
if (wasm === undefined || project === undefined) {
86-
return { rt: undefined, diags: undefined }
91+
let previousState: {
92+
rt: WasmRuntime | undefined
93+
diags: WasmDiagnosticError | undefined
94+
lastValidRt: WasmRuntime | undefined
95+
} = get(runtimeAtom)
96+
return { rt: undefined, diags: undefined, lastValidRt: previousState.lastValidRt }
8797
}
8898
const selectedEnvVars = Object.fromEntries(Object.entries(envVars).filter(([key, value]) => value !== undefined))
8999
const rt = project.runtime(selectedEnvVars)
90100
const diags = project.diagnostics(rt)
91-
return { rt, diags }
101+
return { rt, diags, lastValidRt: rt }
92102
} catch (e) {
93103
console.log('Error occurred while getting runtime', e)
94104
const wasm = get(wasmAtom)
95105
if (wasm) {
96106
const WasmDiagnosticError = wasm.WasmDiagnosticError
97107
if (e instanceof WasmDiagnosticError) {
98-
return { rt: undefined, diags: e }
108+
let previousState: {
109+
rt: WasmRuntime | undefined
110+
diags: WasmDiagnosticError | undefined
111+
lastValidRt: WasmRuntime | undefined
112+
} = get(runtimeAtom)
113+
return { rt: undefined, diags: e, lastValidRt: previousState.lastValidRt }
99114
}
100115
}
101116
if (e instanceof Error) {
@@ -104,7 +119,7 @@ export const runtimeAtom = atom((get) => {
104119
console.error(e)
105120
}
106121
}
107-
return { rt: undefined, diags: undefined }
122+
return { rt: undefined, diags: undefined, lastValidRt: undefined }
108123
})
109124

110125
export const diagnosticsAtom = atom((get) => {

typescript/playground-common/src/shared/baml-project-panel/playground-panel/atoms.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1-
import { atom } from 'jotai'
1+
import { Atom, atom } from 'jotai'
22
import { requiredEnvVarsAtom, envVarsAtom, runtimeAtom } from '../atoms'
33

4-
export const runtimeStateAtom = atom((get) => {
5-
const { rt } = get(runtimeAtom)
4+
export const runtimeStateAtom: Atom<{ functions: WasmFunction[]; stale: boolean }> = atom((get) => {
5+
const { rt, lastValidRt } = get(runtimeAtom)
66
console.log('rt', rt)
77
if (rt === undefined) {
8-
return { functions: [] }
8+
if (lastValidRt === undefined) {
9+
return { functions: [], stale: false }
10+
} else {
11+
return { functions: lastValidRt.list_functions(), stale: true }
12+
}
913
}
1014
const functions = rt.list_functions()
11-
12-
return { functions }
15+
return { functions, stale: false }
1316
})
1417

1518
export const selectedFunctionAtom = atom<string | undefined>(undefined)
@@ -169,7 +172,7 @@ export const areEnvVarsMissingAtom = atom((get) => {
169172
})
170173

171174
// Related to test status
172-
import { type WasmFunctionResponse, type WasmTestResponse } from '@gloo-ai/baml-schema-wasm-web'
175+
import { WasmFunction, type WasmFunctionResponse, type WasmTestResponse } from '@gloo-ai/baml-schema-wasm-web'
173176
import { atomFamily, atomWithStorage } from 'jotai/utils'
174177
import { vscodeLocalStorageStore } from '../Jotai'
175178
import { vscode } from '../vscode'

typescript/playground-common/src/shared/baml-project-panel/playground-panel/side-bar/index.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,22 @@ const functionsAtom = atom((get) => {
4949
}))
5050
})
5151

52+
const functionsAreStaleAtom = atom((get) => {
53+
const runtimeState = get(runtimeStateAtom)
54+
return runtimeState.stale
55+
})
56+
5257
const isEmbed = typeof window !== 'undefined' && window.location.href.includes('embed')
5358

5459
export const isSidebarOpenAtom = atomWithStorage('isSidebarOpen', isEmbed ? false : vscode.isVscode() ? true : false)
5560

5661
export default function CustomSidebar({ isEmbed = false }: { isEmbed?: boolean }) {
5762
const functions = useAtomValue(functionsAtom)
63+
const rtState = useAtomValue(runtimeStateAtom)
5864
const [searchTerm, setSearchTerm] = React.useState('')
5965
const [isOpen, setIsOpen] = useAtom(isSidebarOpenAtom)
6066
const { setRunningTests } = useRunTests()
67+
const functionsAreStale = useAtomValue(functionsAreStaleAtom)
6168

6269
const filteredFunctions = functions.filter(
6370
(func) =>
@@ -79,8 +86,11 @@ export default function CustomSidebar({ isEmbed = false }: { isEmbed?: boolean }
7986
return <></>
8087
}
8188

89+
// Define a mask that will obscure the sidebare if functions are stale.
90+
const maybe_mask = functionsAreStale ? 'pointer-events-none opacity-50' : ''
91+
8292
return (
83-
<div className='flex relative'>
93+
<div className={cn('flex relative', maybe_mask)}>
8494
<Button
8595
onClick={() => setIsOpen(!isOpen)}
8696
variant='ghost'

0 commit comments

Comments
 (0)