Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions app/components/CodeValidationPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,7 @@ export function CodeValidationPanel({ envSpec, onClose }: CodeValidationPanelPro
(i) => i.message.toLowerCase().includes('reward') || i.category === 'security'
)
const terminationIssues = review.issues.filter(
(i) =>
i.message.toLowerCase().includes('terminat') || i.message.toLowerCase().includes('step')
(i) => i.message.toLowerCase().includes('terminat') || i.message.toLowerCase().includes('step')
)
const apiIssues = review.issues.filter((i) => i.category === 'api_compliance')

Expand Down
6 changes: 4 additions & 2 deletions app/components/CodeViewTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
]

export function CodeViewTab({ envSpec }: CodeViewTabProps) {
const [selectedFileType, setSelectedFileType] = useState<string>('environment')
const [selectedFileType, setSelectedFileType] = useState<
'environment' | 'training' | 'config' | 'skypilot' | 'readme' | 'env_spec'
>('environment')
const [code, setCode] = useState<string>('')
const [loading, setLoading] = useState(false)
const [error, setError] = useState<string | null>(null)
Expand Down Expand Up @@ -63,7 +65,7 @@
const startTime = performance.now()
const response = await generateCode({
env_spec: envSpec,
file_type: selectedFileType as any,
file_type: selectedFileType,
training_config: trainingConfig,
algorithm: algorithm,
})
Expand Down Expand Up @@ -209,7 +211,7 @@
</button>
<select
value={selectedFileType}
onChange={(e) => setSelectedFileType(e.target.value)}

Check failure on line 214 in app/components/CodeViewTab.tsx

View workflow job for this annotation

GitHub Actions / ✅ Type Check Frontend (TypeScript)

Argument of type 'string' is not assignable to parameter of type 'SetStateAction<"environment" | "config" | "training" | "skypilot" | "readme" | "env_spec">'.
className="px-3 py-1 text-xs border border-border rounded bg-background"
disabled={loading}
>
Expand Down
2 changes: 1 addition & 1 deletion app/components/EnvironmentCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ export function EnvironmentCard({ env, onUpdate }: EnvironmentCardProps) {
}

return (
<div
<div
className="group relative bg-card border border-border rounded-lg p-5 hover:border-primary/50 transition-all duration-200 cursor-pointer"
onClick={handleCardClick}
>
Expand Down
133 changes: 21 additions & 112 deletions app/components/EnvironmentEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState, useMemo, useEffect, useRef } from 'react'
import { useNavigate } from '@tanstack/react-router'
import { useQuery, useMutation, useAction } from 'convex/react'
import { useQuery, useMutation } from 'convex/react'
import { api } from '../../convex/_generated/api.js'
import { useAuth } from '~/lib/auth'
import { EnvSpec, createDefaultEnvSpec, Vec2 } from '~/lib/envSpec'
Expand All @@ -10,12 +10,6 @@
import { createScene, createSceneVersion, updateScene, getScene } from '~/lib/sceneClient'
import { envSpecToSceneGraph, envSpecToRLConfig } from '~/lib/envSpecToSceneGraph'
import { sceneGraphToEnvSpec } from '~/lib/sceneGraphToEnvSpec'
import { StudioLayout } from './StudioLayout'
import { StudioTopBar } from './StudioTopBar'
import { StudioSidebar } from './StudioSidebar'
import { StudioPropertiesPanel } from './StudioPropertiesPanel'
import { StudioBottomPanel } from './StudioBottomPanel'
import { EnvironmentCanvas } from './EnvironmentCanvas'
import { CreateRun } from './CreateRun'
import { EnhancedImportDialog } from './EnhancedImportDialog'
import { CodeReviewPanel } from './CodeReviewPanel'
Expand Down Expand Up @@ -52,7 +46,6 @@
const [showCodeReview, setShowCodeReview] = useState(false)
const [exportedFiles, setExportedFiles] = useState<Record<string, string> | null>(null)
const [showValidation, setShowValidation] = useState(false)
const [selectedObjectId, setSelectedObjectId] = useState<string | undefined>()
const [selectedAssetId, setSelectedAssetId] = useState<string | undefined>()
const [rolloutState, setRolloutState] = useState<{
agents: Array<{ id: string; position: Vec2 }>
Expand All @@ -61,13 +54,11 @@
// Try to load from Scene Service first, fallback to old system
const [sceneData, setSceneData] = useState<{ scene: any; activeVersion: any } | null>(null)
const [sceneLoading, setSceneLoading] = useState(false)
const [sceneError, setSceneError] = useState<string | null>(null)

// Load from Scene Service if id is provided
useEffect(() => {
if (id !== 'new' && user?._id) {
setSceneLoading(true)
setSceneError(null)
getScene(id)
.then((data) => {
setSceneData(data)
Expand All @@ -76,7 +67,6 @@
.catch((err) => {
// Scene not found in new system - fallback to old system
console.log('Scene not found in Scene Service, falling back to old system:', err)
setSceneError(err.message)
setSceneLoading(false)
})
}
Expand Down Expand Up @@ -147,7 +137,7 @@
const hasAutoCreatedRef = useRef(false)
// Keep a ref to the current localEnvSpec for auto-creation
const localEnvSpecRef = useRef(localEnvSpec)

useEffect(() => {
// Only reset if we just navigated TO 'new' from a different page
if (id === 'new' && prevIdRef.current !== 'new') {
Expand All @@ -156,7 +146,7 @@
}
prevIdRef.current = id
}, [id])

// Auto-create environment when user navigates to /environments/new
useEffect(() => {
if (id === 'new' && user?._id && !hasAutoCreatedRef.current) {
Expand All @@ -166,9 +156,12 @@
const currentSpec = localEnvSpecRef.current
if (id === 'new' && user?._id && !hasAutoCreatedRef.current && currentSpec) {
hasAutoCreatedRef.current = true

console.log('Auto-creating environment...', { userId: user._id, specName: currentSpec.name })


console.log('Auto-creating environment...', {
userId: user._id,
specName: currentSpec.name,
})

try {
// Convert EnvSpec to sceneGraph + rlConfig
const sceneGraph = envSpecToSceneGraph(currentSpec)
Expand Down Expand Up @@ -203,10 +196,13 @@

// Update scene with projectId
await updateScene(sceneId, { projectId: envId })

console.log('Successfully created environment in both systems:', { sceneId, envId })
} catch (oldSystemError) {
console.error('Failed to save to old system (CRITICAL - environment won\'t show in list):', oldSystemError)
console.error(
"Failed to save to old system (CRITICAL - environment won't show in list):",
oldSystemError
)
// This is actually critical - if Convex creation fails, the environment won't show in the list
// because the list queries Convex, not Scene Service
alert('Failed to create environment in database. Please try again.')
Expand Down Expand Up @@ -276,15 +272,15 @@
useEffect(() => {
localEnvSpecRef.current = localEnvSpec
}, [localEnvSpec])

// Sync localEnvSpec when envSpec changes (e.g., template loaded or name updated from database)
// BUT: Don't overwrite if we just set it manually (e.g., from template selection or name change)
useEffect(() => {
// Skip sync if we're in the middle of updating the name
if (isUpdatingNameRef.current) {
return
}

if (id === 'new') {
// Only sync on initial mount, not after manual changes
if (!manuallySetRef.current) {
Expand Down Expand Up @@ -415,21 +411,21 @@
} else {
// Set flag to prevent sync from overwriting our local change
isUpdatingNameRef.current = true

// Update both top-level name and envSpec.name to keep them in sync
const updatedSpec = { ...localEnvSpec, name }

// Update local state immediately for instant UI feedback
setLocalEnvSpec(updatedSpec)

try {
// Update in Convex (old system)
await updateMutation({
id: id as any,
name,
envSpec: updatedSpec, // Also update envSpec.name
})

// Also update Scene Service if scene exists
if (sceneData?.scene) {
try {
Expand Down Expand Up @@ -463,7 +459,7 @@
const handleTestRollout = () => {
// Trigger rollout from bottom panel
if ((window as any).__runRollout) {
;(window as any).__runRollout()

Check failure on line 462 in app/components/EnvironmentEditor.tsx

View workflow job for this annotation

GitHub Actions / ✅ Lint Frontend (ESLint)

Unnecessary semicolon
}
}

Expand Down Expand Up @@ -546,7 +542,7 @@
}
}

const handleDuplicate = async (envId: string) => {
const handleDuplicate = async (_envId: string) => {
// TODO: Implement duplicate
alert('Duplicate coming soon!')
}
Expand All @@ -560,93 +556,6 @@
setShowImport(false)
}

const handleSave = async () => {
if (!user?._id) {
alert('Please log in to create environments')
return
}
try {
// Convert EnvSpec to sceneGraph + rlConfig
const sceneGraph = envSpecToSceneGraph(localEnvSpec)
const rlConfig = envSpecToRLConfig(localEnvSpec)

let sceneId: string
let envId: string

if (id === 'new') {
// Create new scene in Scene Service (primary)
const scene = await createScene({
projectId: '', // Will be set after creating environment
name: localEnvSpec.name || 'Untitled Environment',
description: localEnvSpec.metadata?.notes,
mode: localEnvSpec.world.coordinateSystem === 'grid' ? 'grid' : '2d',
environmentSettings: {},
createdBy: user._id,
})
sceneId = scene.id

// Create initial version
await createSceneVersion(scene.id, {
sceneGraph,
rlConfig,
createdBy: user._id,
})

// Also save to old system for backward compatibility
try {
envId = await createMutation({
ownerId: user._id,
name: localEnvSpec.name || 'Untitled Environment',
envSpec: localEnvSpec,
})

// Update scene with projectId
await updateScene(sceneId, { projectId: envId })
} catch (oldSystemError) {
console.warn('Failed to save to old system (non-critical):', oldSystemError)
// Use scene ID as environment ID
envId = sceneId
}
} else {
// Update existing scene
sceneId = id

// Update scene metadata if name changed
if (localEnvSpec.name && sceneData?.scene.name !== localEnvSpec.name) {
await updateScene(sceneId, {
name: localEnvSpec.name,
description: localEnvSpec.metadata?.notes,
})
}

// Create new version
await createSceneVersion(sceneId, {
sceneGraph,
rlConfig,
createdBy: user._id,
})

// Also update old system for backward compatibility
try {
await updateMutation({
id: id as any,
name: localEnvSpec.name || 'Untitled Environment',
envSpec: localEnvSpec,
})
} catch (oldSystemError) {
console.warn('Failed to update old system (non-critical):', oldSystemError)
}

envId = id
}

navigate({ to: '/environments/$id', params: { id: envId } })
} catch (error) {
console.error('Failed to save environment:', error)
alert('Failed to save environment: ' + (error as Error).message)
}
}

if (isLoading && id !== 'new') {
return (
<div className="h-screen flex items-center justify-center">
Expand Down
16 changes: 8 additions & 8 deletions app/lib/sceneClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,15 @@ export async function getSceneByProjectId(
const convexModule = await import('./convex')
// Access the httpClient - it's not exported, so we need to use the api object
const { api: convexApi } = await import('../../convex/_generated/api')

// Use the Convex HTTP client via the api object
// We need to query scenes:listByProject
const convexUrl = import.meta.env.VITE_CONVEX_URL || import.meta.env.VITE_CONVEX_DEV_URL || ''
if (!convexUrl) {
console.warn('Convex URL not configured')
return null
}

// Query Convex HTTP API directly
const response = await fetch(`${convexUrl}/api/query`, {
method: 'POST',
Expand All @@ -100,23 +100,23 @@ export async function getSceneByProjectId(
args: { projectId },
}),
})

const result = await response.json()

if (result.status === 'error') {
console.warn('Failed to find scene by projectId:', result.errorMessage)
return null
}

const scenes = result.status === 'success' ? result.value : result

if (!scenes || scenes.length === 0) {
return null
}

// Get the first scene (there should only be one per project)
const sceneData = scenes[0]

// Now get the full scene with active version using the scene ID
return await getScene(sceneData._id)
} catch (error) {
Expand Down
2 changes: 0 additions & 2 deletions convex/trainingLogs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,3 @@ export const clear = mutation({
return { deleted: logs.length }
},
})


Loading