@@ -9,15 +9,19 @@ import {
99 Check ,
1010 ChevronDown ,
1111 Clipboard ,
12+ Database ,
1213 Filter ,
1314 FilterX ,
1415 MoreHorizontal ,
16+ Palette ,
17+ Pause ,
1518 RepeatIcon ,
1619 Search ,
1720 SplitIcon ,
1821 Trash2 ,
1922 X ,
2023} from 'lucide-react'
24+ import Link from 'next/link'
2125import { useShallow } from 'zustand/react/shallow'
2226import {
2327 Button ,
@@ -30,6 +34,7 @@ import {
3034 PopoverTrigger ,
3135 Tooltip ,
3236} from '@/components/emcn'
37+ import { getEnv , isTruthy } from '@/lib/core/config/env'
3338import { useRegisterGlobalCommands } from '@/app/workspace/[workspaceId]/providers/global-commands-provider'
3439import { createCommands } from '@/app/workspace/[workspaceId]/utils/commands-utils'
3540import {
@@ -38,6 +43,8 @@ import {
3843 useTerminalResize ,
3944} from '@/app/workspace/[workspaceId]/w/[workflowId]/components/terminal/hooks'
4045import { getBlock } from '@/blocks'
46+ import { useCopilotTrainingStore } from '@/stores/copilot-training/store'
47+ import { useGeneralStore } from '@/stores/settings/general/store'
4148import type { ConsoleEntry } from '@/stores/terminal'
4249import { useTerminalConsoleStore , useTerminalStore } from '@/stores/terminal'
4350import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
@@ -331,6 +338,14 @@ export function Terminal() {
331338 const outputSearchInputRef = useRef < HTMLInputElement > ( null )
332339 const outputContentRef = useRef < HTMLDivElement > ( null )
333340
341+ // Training controls state
342+ const [ isTrainingEnvEnabled , setIsTrainingEnvEnabled ] = useState ( false )
343+ const showTrainingControls = useGeneralStore ( ( state ) => state . showTrainingControls )
344+ const { isTraining, toggleModal : toggleTrainingModal , stopTraining } = useCopilotTrainingStore ( )
345+
346+ // Playground state
347+ const [ isPlaygroundEnabled , setIsPlaygroundEnabled ] = useState ( false )
348+
334349 // Terminal resize hooks
335350 const { handleMouseDown } = useTerminalResize ( )
336351 const { handleMouseDown : handleOutputPanelResizeMouseDown } = useOutputPanelResize ( )
@@ -612,6 +627,26 @@ export function Terminal() {
612627 [ activeWorkflowId , exportConsoleCSV ]
613628 )
614629
630+ /**
631+ * Handle training button click - toggle training state or open modal
632+ */
633+ const handleTrainingClick = useCallback (
634+ ( e : React . MouseEvent ) => {
635+ e . stopPropagation ( )
636+ if ( isTraining ) {
637+ stopTraining ( )
638+ } else {
639+ toggleTrainingModal ( )
640+ }
641+ } ,
642+ [ isTraining , stopTraining , toggleTrainingModal ]
643+ )
644+
645+ /**
646+ * Whether training controls should be visible
647+ */
648+ const shouldShowTrainingButton = isTrainingEnvEnabled && showTrainingControls
649+
615650 /**
616651 * Register global keyboard shortcuts for the terminal:
617652 * - Mod+D: Clear terminal console for the active workflow
@@ -640,6 +675,14 @@ export function Terminal() {
640675 setHasHydrated ( true )
641676 } , [ setHasHydrated ] )
642677
678+ /**
679+ * Check environment variables on mount
680+ */
681+ useEffect ( ( ) => {
682+ setIsTrainingEnvEnabled ( isTruthy ( getEnv ( 'NEXT_PUBLIC_COPILOT_TRAINING_ENABLED' ) ) )
683+ setIsPlaygroundEnabled ( isTruthy ( getEnv ( 'NEXT_PUBLIC_ENABLE_PLAYGROUND' ) ) )
684+ } , [ ] )
685+
643686 /**
644687 * Adjust showInput when selected entry changes
645688 * Stay on input view if the new entry has input data
@@ -1104,6 +1147,48 @@ export function Terminal() {
11041147 ) }
11051148 { ! selectedEntry && (
11061149 < div className = 'ml-auto flex items-center gap-[8px]' >
1150+ { isPlaygroundEnabled && (
1151+ < Tooltip . Root >
1152+ < Tooltip . Trigger asChild >
1153+ < Link href = '/playground' >
1154+ < Button
1155+ variant = 'ghost'
1156+ aria-label = 'Component Playground'
1157+ className = '!p-1.5 -m-1.5'
1158+ >
1159+ < Palette className = 'h-3 w-3' />
1160+ </ Button >
1161+ </ Link >
1162+ </ Tooltip . Trigger >
1163+ < Tooltip . Content >
1164+ < span > Component Playground</ span >
1165+ </ Tooltip . Content >
1166+ </ Tooltip . Root >
1167+ ) }
1168+ { shouldShowTrainingButton && (
1169+ < Tooltip . Root >
1170+ < Tooltip . Trigger asChild >
1171+ < Button
1172+ variant = 'ghost'
1173+ onClick = { handleTrainingClick }
1174+ aria-label = { isTraining ? 'Stop training' : 'Train Copilot' }
1175+ className = { clsx (
1176+ '!p-1.5 -m-1.5' ,
1177+ isTraining && 'text-orange-600 dark:text-orange-400'
1178+ ) }
1179+ >
1180+ { isTraining ? (
1181+ < Pause className = 'h-3 w-3' />
1182+ ) : (
1183+ < Database className = 'h-3 w-3' />
1184+ ) }
1185+ </ Button >
1186+ </ Tooltip . Trigger >
1187+ < Tooltip . Content >
1188+ < span > { isTraining ? 'Stop Training' : 'Train Copilot' } </ span >
1189+ </ Tooltip . Content >
1190+ </ Tooltip . Root >
1191+ ) }
11071192 { hasActiveFilters && (
11081193 < Tooltip . Root >
11091194 < Tooltip . Trigger asChild >
@@ -1426,6 +1511,50 @@ export function Terminal() {
14261511 </ Tooltip . Root >
14271512 ) }
14281513
1514+ { isPlaygroundEnabled && (
1515+ < Tooltip . Root >
1516+ < Tooltip . Trigger asChild >
1517+ < Link href = '/playground' >
1518+ < Button
1519+ variant = 'ghost'
1520+ aria-label = 'Component Playground'
1521+ className = '!p-1.5 -m-1.5'
1522+ >
1523+ < Palette className = 'h-[12px] w-[12px]' />
1524+ </ Button >
1525+ </ Link >
1526+ </ Tooltip . Trigger >
1527+ < Tooltip . Content >
1528+ < span > Component Playground</ span >
1529+ </ Tooltip . Content >
1530+ </ Tooltip . Root >
1531+ ) }
1532+
1533+ { shouldShowTrainingButton && (
1534+ < Tooltip . Root >
1535+ < Tooltip . Trigger asChild >
1536+ < Button
1537+ variant = 'ghost'
1538+ onClick = { handleTrainingClick }
1539+ aria-label = { isTraining ? 'Stop training' : 'Train Copilot' }
1540+ className = { clsx (
1541+ '!p-1.5 -m-1.5' ,
1542+ isTraining && 'text-orange-600 dark:text-orange-400'
1543+ ) }
1544+ >
1545+ { isTraining ? (
1546+ < Pause className = 'h-[12px] w-[12px]' />
1547+ ) : (
1548+ < Database className = 'h-[12px] w-[12px]' />
1549+ ) }
1550+ </ Button >
1551+ </ Tooltip . Trigger >
1552+ < Tooltip . Content >
1553+ < span > { isTraining ? 'Stop Training' : 'Train Copilot' } </ span >
1554+ </ Tooltip . Content >
1555+ </ Tooltip . Root >
1556+ ) }
1557+
14291558 < Tooltip . Root >
14301559 < Tooltip . Trigger asChild >
14311560 < Button
0 commit comments