@@ -51,7 +51,6 @@ import {
5151} from 'lucide-react'
5252import { useParams , useRouter , useSearchParams } from 'next/navigation'
5353import ReactMarkdown from 'react-markdown'
54- import { Tooltip } from '@/components/emcn'
5554import { Badge } from '@/components/ui/badge'
5655import { Button } from '@/components/ui/button'
5756import {
@@ -60,6 +59,7 @@ import {
6059 DropdownMenuItem ,
6160 DropdownMenuTrigger ,
6261} from '@/components/ui/dropdown-menu'
62+ import { useSession } from '@/lib/auth-client'
6363import { createLogger } from '@/lib/logs/console/logger'
6464import { cn } from '@/lib/utils'
6565import type { CredentialRequirement } from '@/lib/workflows/credential-extractor'
@@ -110,14 +110,19 @@ const iconMap = {
110110 Award,
111111}
112112
113- export default function TemplateDetails ( ) {
113+ interface TemplateDetailsProps {
114+ isWorkspaceContext ?: boolean
115+ }
116+
117+ export default function TemplateDetails ( { isWorkspaceContext = false } : TemplateDetailsProps ) {
114118 const router = useRouter ( )
115119 const searchParams = useSearchParams ( )
116120 const params = useParams ( )
117121 const templateId = params ?. id as string
122+ const workspaceId = isWorkspaceContext ? ( params ?. workspaceId as string ) : null
123+ const { data : session } = useSession ( )
118124
119125 const [ template , setTemplate ] = useState < Template | null > ( null )
120- const [ currentUserId , setCurrentUserId ] = useState < string | null > ( null )
121126 const [ currentUserOrgs , setCurrentUserOrgs ] = useState < string [ ] > ( [ ] )
122127 const [ currentUserOrgRoles , setCurrentUserOrgRoles ] = useState <
123128 Array < { organizationId : string ; role : string } >
@@ -139,6 +144,8 @@ export default function TemplateDetails() {
139144 const [ showWorkspaceSelectorForEdit , setShowWorkspaceSelectorForEdit ] = useState ( false )
140145 const [ showWorkspaceSelectorForUse , setShowWorkspaceSelectorForUse ] = useState ( false )
141146
147+ const currentUserId = session ?. user ?. id || null
148+
142149 // Fetch template data on client side
143150 useEffect ( ( ) => {
144151 if ( ! templateId ) {
@@ -156,28 +163,15 @@ export default function TemplateDetails() {
156163 setStarCount ( data . data . stars || 0 )
157164 }
158165 } catch ( error ) {
159- console . error ( 'Error fetching template:' , error )
166+ logger . error ( 'Error fetching template:' , error )
160167 } finally {
161168 setLoading ( false )
162169 }
163170 }
164171
165- const fetchCurrentUser = async ( ) => {
166- try {
167- const response = await fetch ( '/api/auth/get-session' )
168- if ( response . ok ) {
169- const data = await response . json ( )
170- setCurrentUserId ( data ?. user ?. id || null )
171- } else {
172- setCurrentUserId ( null )
173- }
174- } catch ( error ) {
175- console . error ( 'Error fetching session:' , error )
176- setCurrentUserId ( null )
177- }
178- }
179-
180172 const fetchUserOrganizations = async ( ) => {
173+ if ( ! currentUserId ) return
174+
181175 try {
182176 const response = await fetch ( '/api/organizations' )
183177 if ( response . ok ) {
@@ -192,27 +186,28 @@ export default function TemplateDetails() {
192186 setCurrentUserOrgRoles ( orgRoles )
193187 }
194188 } catch ( error ) {
195- console . error ( 'Error fetching organizations:' , error )
189+ logger . error ( 'Error fetching organizations:' , error )
196190 }
197191 }
198192
199193 const fetchSuperUserStatus = async ( ) => {
194+ if ( ! currentUserId ) return
195+
200196 try {
201197 const response = await fetch ( '/api/user/super-user' )
202198 if ( response . ok ) {
203199 const data = await response . json ( )
204200 setIsSuperUser ( data . isSuperUser || false )
205201 }
206202 } catch ( error ) {
207- console . error ( 'Error fetching super user status:' , error )
203+ logger . error ( 'Error fetching super user status:' , error )
208204 }
209205 }
210206
211207 fetchTemplate ( )
212- fetchCurrentUser ( )
213208 fetchSuperUserStatus ( )
214209 fetchUserOrganizations ( )
215- } , [ templateId ] )
210+ } , [ templateId , currentUserId ] )
216211
217212 // Fetch workspaces when user is logged in
218213 useEffect ( ( ) => {
@@ -235,7 +230,7 @@ export default function TemplateDetails() {
235230 setWorkspaces ( availableWorkspaces )
236231 }
237232 } catch ( error ) {
238- console . error ( 'Error fetching workspaces:' , error )
233+ logger . error ( 'Error fetching workspaces:' , error )
239234 } finally {
240235 setIsLoadingWorkspaces ( false )
241236 }
@@ -247,9 +242,14 @@ export default function TemplateDetails() {
247242 // Clean up URL when returning from login
248243 useEffect ( ( ) => {
249244 if ( template && searchParams ?. get ( 'use' ) === 'true' && currentUserId ) {
250- router . replace ( `/templates/${ template . id } ` )
245+ if ( isWorkspaceContext && workspaceId ) {
246+ handleWorkspaceSelectForUse ( workspaceId )
247+ router . replace ( `/workspace/${ workspaceId } /templates/${ template . id } ` )
248+ } else {
249+ router . replace ( `/templates/${ template . id } ` )
250+ }
251251 }
252- } , [ searchParams , currentUserId , template , router ] )
252+ } , [ searchParams , currentUserId , template , isWorkspaceContext , workspaceId , router ] )
253253
254254 // Check if user can edit template
255255 const canEditTemplate = ( ( ) => {
@@ -355,7 +355,7 @@ export default function TemplateDetails() {
355355 />
356356 )
357357 } catch ( error ) {
358- console . error ( 'Error rendering workflow preview:' , error )
358+ logger . error ( 'Error rendering workflow preview:' , error )
359359 return (
360360 < div className = 'flex h-full items-center justify-center text-center' >
361361 < div className = 'text-muted-foreground' >
@@ -368,7 +368,11 @@ export default function TemplateDetails() {
368368 }
369369
370370 const handleBack = ( ) => {
371- router . push ( '/templates' )
371+ if ( isWorkspaceContext ) {
372+ router . back ( )
373+ } else {
374+ router . push ( '/templates' )
375+ }
372376 }
373377
374378 const handleStarToggle = async ( ) => {
@@ -392,37 +396,59 @@ export default function TemplateDetails() {
392396
393397 const handleUseTemplate = ( ) => {
394398 if ( ! currentUserId ) {
395- const callbackUrl = encodeURIComponent ( `/templates/${ template . id } ` )
399+ const callbackUrl =
400+ isWorkspaceContext && workspaceId
401+ ? encodeURIComponent ( `/workspace/${ workspaceId } /templates/${ template . id } ?use=true` )
402+ : encodeURIComponent ( `/templates/${ template . id } ` )
396403 router . push ( `/login?callbackUrl=${ callbackUrl } ` )
397404 return
398405 }
399- setShowWorkspaceSelectorForUse ( true )
406+
407+ // In workspace context, use current workspace directly
408+ if ( isWorkspaceContext && workspaceId ) {
409+ handleWorkspaceSelectForUse ( workspaceId )
410+ } else {
411+ setShowWorkspaceSelectorForUse ( true )
412+ }
400413 }
401414
402415 const handleEditTemplate = async ( ) => {
403416 if ( ! currentUserId || ! template ) return
404417
405- // Check if workflow exists and user has access
406- if ( template . workflowId ) {
418+ // In workspace context with existing workflow, navigate directly
419+ if ( isWorkspaceContext && workspaceId && template . workflowId ) {
420+ setIsEditing ( true )
421+ try {
422+ const checkResponse = await fetch ( `/api/workflows/${ template . workflowId } ` )
423+
424+ if ( checkResponse . ok ) {
425+ router . push ( `/workspace/${ workspaceId } /w/${ template . workflowId } ` )
426+ return
427+ }
428+ } catch ( error ) {
429+ logger . error ( 'Error checking workflow:' , error )
430+ } finally {
431+ setIsEditing ( false )
432+ }
433+ // If workflow doesn't exist, fall through to workspace selector
434+ }
435+
436+ // Check if workflow exists and user has access (global context)
437+ if ( template . workflowId && ! isWorkspaceContext ) {
407438 setIsEditing ( true )
408439 try {
409440 const checkResponse = await fetch ( `/api/workflows/${ template . workflowId } ` )
410441
411442 if ( checkResponse . status === 403 ) {
412- // User doesn't have access to the workspace
413- // This shouldn't happen if button is properly disabled, but handle it gracefully
414443 alert ( "You don't have access to the workspace containing this template" )
415444 return
416445 }
417446
418447 if ( checkResponse . ok ) {
419- // Workflow exists and user has access, get its workspace and navigate to it
420448 const result = await checkResponse . json ( )
421- const workspaceId = result . data ?. workspaceId
422- if ( workspaceId ) {
423- // Use window.location to ensure a full page load with fresh data
424- // This avoids race conditions with client-side navigation
425- window . location . href = `/workspace/${ workspaceId } /w/${ template . workflowId } `
449+ const templateWorkspaceId = result . data ?. workspaceId
450+ if ( templateWorkspaceId ) {
451+ window . location . href = `/workspace/${ templateWorkspaceId } /w/${ template . workflowId } `
426452 return
427453 }
428454 }
@@ -433,8 +459,12 @@ export default function TemplateDetails() {
433459 }
434460 }
435461
436- // Workflow doesn't exist or was deleted - show workspace selector
437- setShowWorkspaceSelectorForEdit ( true )
462+ // Workflow doesn't exist - show workspace selector or use current workspace
463+ if ( isWorkspaceContext && workspaceId ) {
464+ handleWorkspaceSelectForEdit ( workspaceId )
465+ } else {
466+ setShowWorkspaceSelectorForEdit ( true )
467+ }
438468 }
439469
440470 const handleWorkspaceSelectForUse = async ( workspaceId : string ) => {
@@ -505,7 +535,11 @@ export default function TemplateDetails() {
505535 // Update template status optimistically
506536 setTemplate ( { ...template , status : 'approved' } )
507537 // Redirect back to templates page after approval
508- router . push ( '/templates' )
538+ if ( isWorkspaceContext && workspaceId ) {
539+ router . push ( `/workspace/${ workspaceId } /templates` )
540+ } else {
541+ router . push ( '/templates' )
542+ }
509543 }
510544 } catch ( error ) {
511545 logger . error ( 'Error approving template:' , error )
@@ -527,7 +561,11 @@ export default function TemplateDetails() {
527561 // Update template status optimistically
528562 setTemplate ( { ...template , status : 'rejected' } )
529563 // Redirect back to templates page after rejection
530- router . push ( '/templates' )
564+ if ( isWorkspaceContext && workspaceId ) {
565+ router . push ( `/workspace/${ workspaceId } /templates` )
566+ } else {
567+ router . push ( '/templates' )
568+ }
531569 }
532570 } catch ( error ) {
533571 logger . error ( 'Error rejecting template:' , error )
@@ -537,7 +575,7 @@ export default function TemplateDetails() {
537575 }
538576
539577 return (
540- < div className = 'flex min-h-screen flex-col' >
578+ < div className = { cn ( 'flex min-h-screen flex-col' , isWorkspaceContext && 'pl-64' ) } >
541579 { /* Header */ }
542580 < div className = 'border-b bg-background p-6' >
543581 < div className = 'mx-auto max-w-7xl' >
@@ -621,42 +659,25 @@ export default function TemplateDetails() {
621659 </ Button >
622660 ) }
623661
624- { /* Edit button - for template owners (approved or pending) */ }
662+ { /* Edit button - for template owners */ }
625663 { canEditTemplate && currentUserId && (
626664 < >
627- { template . workflowId && ! showWorkspaceSelectorForEdit ? (
628- < Tooltip . Root >
629- < Tooltip . Trigger asChild >
630- < span >
631- < Button
632- onClick = { handleEditTemplate }
633- disabled = { isEditing || hasWorkspaceAccess === false }
634- className = {
635- hasWorkspaceAccess === false
636- ? 'cursor-not-allowed opacity-50'
637- : 'bg-blue-600 text-white hover:bg-blue-700'
638- }
639- >
640- { isEditing ? 'Opening...' : 'Edit Template' }
641- </ Button >
642- </ span >
643- </ Tooltip . Trigger >
644- { hasWorkspaceAccess === false && (
645- < Tooltip . Content >
646- < p > Don't have access to workspace to edit template</ p >
647- </ Tooltip . Content >
648- ) }
649- </ Tooltip . Root >
665+ { ( isWorkspaceContext || template . workflowId ) && ! showWorkspaceSelectorForEdit ? (
666+ < Button
667+ onClick = { handleEditTemplate }
668+ disabled = { isEditing || ( ! isWorkspaceContext && hasWorkspaceAccess === false ) }
669+ className = 'bg-blue-600 text-white hover:bg-blue-700'
670+ >
671+ { isEditing ? 'Opening...' : 'Edit Template' }
672+ </ Button >
650673 ) : (
651674 < DropdownMenu
652675 open = { showWorkspaceSelectorForEdit }
653676 onOpenChange = { setShowWorkspaceSelectorForEdit }
654677 >
655678 < DropdownMenuTrigger asChild >
656679 < Button
657- onClick = { ( ) =>
658- ! template . workflowId && setShowWorkspaceSelectorForEdit ( true )
659- }
680+ onClick = { ( ) => setShowWorkspaceSelectorForEdit ( true ) }
660681 disabled = { isUsing || isLoadingWorkspaces }
661682 className = 'bg-blue-600 text-white hover:bg-blue-700'
662683 >
@@ -701,13 +722,26 @@ export default function TemplateDetails() {
701722 { ! currentUserId ? (
702723 < Button
703724 onClick = { ( ) => {
704- const callbackUrl = encodeURIComponent ( `/templates/${ template . id } ` )
725+ const callbackUrl =
726+ isWorkspaceContext && workspaceId
727+ ? encodeURIComponent (
728+ `/workspace/${ workspaceId } /templates/${ template . id } ?use=true`
729+ )
730+ : encodeURIComponent ( `/templates/${ template . id } ` )
705731 router . push ( `/login?callbackUrl=${ callbackUrl } ` )
706732 } }
707733 className = 'bg-purple-600 text-white hover:bg-purple-700'
708734 >
709735 Sign in to use
710736 </ Button >
737+ ) : isWorkspaceContext ? (
738+ < Button
739+ onClick = { handleUseTemplate }
740+ disabled = { isUsing }
741+ className = 'bg-purple-600 text-white hover:bg-purple-700'
742+ >
743+ { isUsing ? 'Creating...' : 'Use this template' }
744+ </ Button >
711745 ) : (
712746 < DropdownMenu
713747 open = { showWorkspaceSelectorForUse }
0 commit comments