@@ -27,7 +27,7 @@ import { ModelOption } from './modelSelector.tsx';
2727import { ActionArtifactRenderer } from './ActionArtifactRenderer' ;
2828import ChatStatusDisplay from './ChatStatusDisplay.tsx' ;
2929import StaktrakRecorder from './StaktrakRecorder' ;
30-
30+ import axios from 'axios' ;
3131import SplashScreen from './ChatSplashScreen' ;
3232
3333interface RouteParams {
@@ -640,6 +640,10 @@ export const HiveChatView: React.FC = observer(() => {
640640 const [ sseLogs , setSseLogs ] = useState < SSEMessage [ ] > ( [ ] ) ;
641641 const [ , setStaktrakReady ] = useState ( false ) ;
642642 const [ iframeUrl , setIframeUrl ] = useState ( '' ) ;
643+ const [ isWorkspaceComplete , setIsWorkspaceComplete ] = useState < boolean > ( false ) ;
644+ const [ isPATExpired , setIsPATExpired ] = useState < boolean > ( false ) ;
645+ const [ isValidating , setIsValidating ] = useState < boolean > ( true ) ;
646+ const [ workspaceData , setWorkspaceData ] = useState < any > ( null ) ;
643647 useBrowserTabTitle ( 'Hive Chat' ) ;
644648
645649 if ( isVerboseLoggingEnabled ) {
@@ -791,6 +795,19 @@ export const HiveChatView: React.FC = observer(() => {
791795 const messageText = messageToSend || message ;
792796 if ( ! messageText . trim ( ) || isSending ) return ;
793797
798+ if ( ! isWorkspaceComplete || isPATExpired ) {
799+ ui . setToasts ( [
800+ {
801+ title : 'Cannot Send Message' ,
802+ color : 'danger' ,
803+ text : isPATExpired
804+ ? 'Your GitHub PAT has expired. Please update it in settings.'
805+ : 'Your workspace setup is incomplete. Please check settings.'
806+ }
807+ ] ) ;
808+ return ;
809+ }
810+
794811 setIsSending ( true ) ;
795812 try {
796813 if ( messageText . includes ( '@Testing' ) ) {
@@ -1341,6 +1358,18 @@ export const HiveChatView: React.FC = observer(() => {
13411358 ( textArtifact && textArtifact . length > 0 ) ;
13421359
13431360 const handleSplashMessage = async ( msg : string ) => {
1361+ if ( ! isWorkspaceComplete || isPATExpired ) {
1362+ ui . setToasts ( [
1363+ {
1364+ title : 'Cannot Send Message' ,
1365+ color : 'danger' ,
1366+ text : isPATExpired
1367+ ? 'Your GitHub PAT has expired. Please update it in settings.'
1368+ : 'Your workspace setup is incomplete. Please check settings.'
1369+ }
1370+ ] ) ;
1371+ return ;
1372+ }
13441373 setMessage ( msg ) ;
13451374 setIsSending ( true ) ;
13461375
@@ -1835,7 +1864,76 @@ export const HiveChatView: React.FC = observer(() => {
18351864 }
18361865 } , [ isTestingMode , artifactTab ] ) ;
18371866
1838- if ( loading ) {
1867+ const validateGitHubPAT = async ( pat : string ) : Promise < boolean > => {
1868+ if ( ! pat ) return false ;
1869+
1870+ try {
1871+ const response = await axios . get ( 'https://api.github.com/user' , {
1872+ headers : {
1873+ Authorization : `token ${ pat } `
1874+ }
1875+ } ) ;
1876+
1877+ return response . status === 200 ;
1878+ } catch ( error ) {
1879+ console . error ( 'Error validating GitHub PAT:' , error ) ;
1880+ return false ;
1881+ }
1882+ } ;
1883+
1884+ const checkWorkspaceSetup = useCallback ( async ( ) => {
1885+ if ( ! uuid ) return ;
1886+
1887+ setIsValidating ( true ) ;
1888+ try {
1889+ const workspace = await main . getUserWorkspaceByUuid ( uuid ) ;
1890+ setWorkspaceData ( workspace ) ;
1891+
1892+ if ( ! workspace ) {
1893+ setIsWorkspaceComplete ( false ) ;
1894+ setIsValidating ( false ) ;
1895+ return ;
1896+ }
1897+
1898+ const codeGraph = await main . getWorkspaceCodeGraph ( uuid ) ;
1899+
1900+ const hasCodeGraphUrl = codeGraph && codeGraph . url ;
1901+ const hasSecretAlias = codeGraph && codeGraph . secret_alias ;
1902+
1903+ let patValid = false ;
1904+ const codeSpaceConfig = await main . getCodeSpaceConfig ( uuid ) ;
1905+
1906+ const hasCodespaceUrl = codeSpaceConfig && codeSpaceConfig . url ;
1907+ const hasUsername = codeSpaceConfig && codeSpaceConfig . username ;
1908+ const hasPAT = codeSpaceConfig && codeSpaceConfig . pat ;
1909+
1910+ if ( hasPAT ) {
1911+ patValid = await validateGitHubPAT ( codeSpaceConfig . pat ) ;
1912+ setIsPATExpired ( ! ! ( ! patValid && hasPAT ) ) ;
1913+ }
1914+
1915+ const isComplete = ! ! (
1916+ hasCodeGraphUrl &&
1917+ hasSecretAlias &&
1918+ hasCodespaceUrl &&
1919+ hasUsername &&
1920+ hasPAT &&
1921+ patValid
1922+ ) ;
1923+ setIsWorkspaceComplete ( isComplete ) ;
1924+ } catch ( error ) {
1925+ console . error ( 'Error checking workspace setup:' , error ) ;
1926+ setIsWorkspaceComplete ( false ) ;
1927+ } finally {
1928+ setIsValidating ( false ) ;
1929+ }
1930+ } , [ uuid , main ] ) ;
1931+
1932+ useEffect ( ( ) => {
1933+ checkWorkspaceSetup ( ) ;
1934+ } , [ checkWorkspaceSetup ] ) ;
1935+
1936+ if ( loading || isValidating ) {
18391937 return (
18401938 < Container collapsed = { collapsed } ref = { containerRef } >
18411939 < LoadingContainer >
@@ -1902,6 +2000,10 @@ export const HiveChatView: React.FC = observer(() => {
19022000 < SplashScreen
19032001 user = { { alias : ui . meInfo ?. owner_alias || 'User' } }
19042002 onSendMessage = { handleSplashMessage }
2003+ isWorkspaceIncomplete = { ! isWorkspaceComplete }
2004+ isPATExpired = { isPATExpired }
2005+ workspaceUuid = { uuid }
2006+ disableInput = { ! isWorkspaceComplete || isPATExpired }
19052007 />
19062008 </ SplashContainer >
19072009 ) }
@@ -1975,18 +2077,25 @@ export const HiveChatView: React.FC = observer(() => {
19752077 value = { message }
19762078 onChange = { handleMessageChange }
19772079 onKeyPress = { handleKeyPress }
1978- placeholder = "Type your message..."
1979- disabled = { isSending }
2080+ placeholder = {
2081+ ! isWorkspaceComplete || isPATExpired
2082+ ? 'Complete workspace setup to send messages'
2083+ : 'Type your message...'
2084+ }
2085+ disabled = { isSending || ! isWorkspaceComplete || isPATExpired }
19802086 />
19812087 { isPdfUploadEnabled && (
1982- < AttachButton onClick = { ( ) => setIsUploadModalOpen ( true ) } disabled = { isSending } >
2088+ < AttachButton
2089+ onClick = { ( ) => setIsUploadModalOpen ( true ) }
2090+ disabled = { isSending || ! isWorkspaceComplete || isPATExpired }
2091+ >
19832092 Attach
19842093 < AttachIcon icon = "attach_file" />
19852094 </ AttachButton >
19862095 ) }
19872096 < SendButton
19882097 onClick = { ( ) => handleSendMessage ( ) }
1989- disabled = { ! message . trim ( ) || isSending }
2098+ disabled = { ! message . trim ( ) || isSending || ! isWorkspaceComplete || isPATExpired }
19902099 >
19912100 Send
19922101 </ SendButton >
0 commit comments