1- import type { UserMessage } from "@opencode-ai/sdk/v2"
1+ import type { Project , UserMessage } from "@opencode-ai/sdk/v2"
22import { useDialog } from "@opencode-ai/ui/context/dialog"
33import {
44 onCleanup ,
@@ -20,11 +20,13 @@ import { createStore } from "solid-js/store"
2020import { ResizeHandle } from "@opencode-ai/ui/resize-handle"
2121import { Select } from "@opencode-ai/ui/select"
2222import { createAutoScroll } from "@opencode-ai/ui/hooks"
23- import { Mark } from "@opencode-ai/ui/logo"
23+ import { Button } from "@opencode-ai/ui/button"
24+ import { showToast } from "@opencode-ai/ui/toast"
2425import { base64Encode , checksum } from "@opencode-ai/util/encode"
2526import { useNavigate , useParams , useSearchParams } from "@solidjs/router"
2627import { NewSessionView , SessionHeader } from "@/components/session"
2728import { useComments } from "@/context/comments"
29+ import { useGlobalSync } from "@/context/global-sync"
2830import { useLanguage } from "@/context/language"
2931import { useLayout } from "@/context/layout"
3032import { usePrompt } from "@/context/prompt"
@@ -41,6 +43,7 @@ import { TerminalPanel } from "@/pages/session/terminal-panel"
4143import { useSessionCommands } from "@/pages/session/use-session-commands"
4244import { useSessionHashScroll } from "@/pages/session/use-session-hash-scroll"
4345import { same } from "@/utils/same"
46+ import { formatServerError } from "@/utils/server-errors"
4447
4548const emptyUserMessages : UserMessage [ ] = [ ]
4649
@@ -252,6 +255,7 @@ function createSessionHistoryWindow(input: SessionHistoryWindowInput) {
252255}
253256
254257export default function Page ( ) {
258+ const globalSync = useGlobalSync ( )
255259 const layout = useLayout ( )
256260 const local = useLocal ( )
257261 const file = useFile ( )
@@ -278,6 +282,7 @@ export default function Page() {
278282 } )
279283
280284 const [ ui , setUi ] = createStore ( {
285+ git : false ,
281286 pendingMessage : undefined as string | undefined ,
282287 scrollGesture : 0 ,
283288 scroll : {
@@ -494,6 +499,46 @@ export default function Page() {
494499 return "session.review.noVcs"
495500 } )
496501
502+ function upsert ( next : Project ) {
503+ const list = globalSync . data . project
504+ sync . set ( "project" , next . id )
505+ const idx = list . findIndex ( ( item ) => item . id === next . id )
506+ if ( idx >= 0 ) {
507+ globalSync . set (
508+ "project" ,
509+ list . map ( ( item , i ) => ( i === idx ? { ...item , ...next } : item ) ) ,
510+ )
511+ return
512+ }
513+ const at = list . findIndex ( ( item ) => item . id > next . id )
514+ if ( at >= 0 ) {
515+ globalSync . set ( "project" , [ ...list . slice ( 0 , at ) , next , ...list . slice ( at ) ] )
516+ return
517+ }
518+ globalSync . set ( "project" , [ ...list , next ] )
519+ }
520+
521+ function initGit ( ) {
522+ if ( ui . git ) return
523+ setUi ( "git" , true )
524+ void sdk . client . project
525+ . initGit ( )
526+ . then ( ( x ) => {
527+ if ( ! x . data ) return
528+ upsert ( x . data )
529+ } )
530+ . catch ( ( err ) => {
531+ showToast ( {
532+ variant : "error" ,
533+ title : language . t ( "common.requestFailed" ) ,
534+ description : formatServerError ( err , language . t ) ,
535+ } )
536+ } )
537+ . finally ( ( ) => {
538+ setUi ( "git" , false )
539+ } )
540+ }
541+
497542 let inputRef ! : HTMLDivElement
498543 let promptDock : HTMLDivElement | undefined
499544 let dockHeight = 0
@@ -727,23 +772,28 @@ export default function Page() {
727772 const changesOptions = [ "session" , "turn" ] as const
728773 const changesOptionsList = [ ...changesOptions ]
729774
730- const changesTitle = ( ) => (
731- < Select
732- options = { changesOptionsList }
733- current = { store . changes }
734- label = { ( option ) =>
735- option === "session" ? language . t ( "ui.sessionReview.title" ) : language . t ( "ui.sessionReview.title.lastTurn" )
736- }
737- onSelect = { ( option ) => option && setStore ( "changes" , option ) }
738- variant = "ghost"
739- size = "small"
740- valueClass = "text-14-medium"
741- />
742- )
775+ const changesTitle = ( ) => {
776+ if ( ! hasReview ( ) ) {
777+ return null
778+ }
779+
780+ return (
781+ < Select
782+ options = { changesOptionsList }
783+ current = { store . changes }
784+ label = { ( option ) =>
785+ option === "session" ? language . t ( "ui.sessionReview.title" ) : language . t ( "ui.sessionReview.title.lastTurn" )
786+ }
787+ onSelect = { ( option ) => option && setStore ( "changes" , option ) }
788+ variant = "ghost"
789+ size = "small"
790+ valueClass = "text-14-medium"
791+ />
792+ )
793+ }
743794
744795 const emptyTurn = ( ) => (
745796 < div class = "h-full pb-30 flex flex-col items-center justify-center text-center gap-6" >
746- < Mark class = "w-14 opacity-10" />
747797 < div class = "text-14-regular text-text-weak max-w-56" > { language . t ( "session.review.noChanges" ) } </ div >
748798 </ div >
749799 )
@@ -809,9 +859,23 @@ export default function Page() {
809859 empty = {
810860 store . changes === "turn" ? (
811861 emptyTurn ( )
862+ ) : reviewEmptyKey ( ) === "session.review.noVcs" ? (
863+ < div class = { input . emptyClass } >
864+ < div class = "flex flex-col gap-3" >
865+ < div class = "text-14-medium text-text-strong" > Create a Git repository</ div >
866+ < div
867+ class = "text-14-regular text-text-base max-w-md"
868+ style = { { "line-height" : "var(--line-height-normal)" } }
869+ >
870+ Track, review, and undo changes in this project
871+ </ div >
872+ </ div >
873+ < Button size = "large" disabled = { ui . git } onClick = { initGit } >
874+ { ui . git ? "Creating Git repository..." : "Create Git repository" }
875+ </ Button >
876+ </ div >
812877 ) : (
813878 < div class = { input . emptyClass } >
814- < Mark class = "w-14 opacity-10" />
815879 < div class = "text-14-regular text-text-weak max-w-56" > { language . t ( reviewEmptyKey ( ) ) } </ div >
816880 </ div >
817881 )
0 commit comments