mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-10 23:48:09 -05:00
fix(templates-details): restore approval feature, and keep details UI consistent, smoothen out creation of profile (#1943)
* fix(templates): view current ui * update UI to be less cluttered * make state management for creating user profile smoother * fix autoselect logic * fix lint
This commit is contained in:
committed by
GitHub
parent
79b318fd9c
commit
dbf9097a5b
@@ -651,10 +651,10 @@ export default function TemplateDetails({ isWorkspaceContext = false }: Template
|
||||
className={cn(
|
||||
'transition-colors',
|
||||
isStarred &&
|
||||
'border-yellow-200 bg-yellow-50 text-yellow-700 hover:bg-yellow-100'
|
||||
'border-yellow-500/50 bg-yellow-500/10 text-yellow-500 hover:bg-yellow-500/20'
|
||||
)}
|
||||
>
|
||||
<Star className={cn('mr-2 h-4 w-4', isStarred && 'fill-current')} />
|
||||
<Star className={cn('mr-2 h-4 w-4', isStarred && 'fill-yellow-500')} />
|
||||
{starCount}
|
||||
</Button>
|
||||
)}
|
||||
@@ -837,14 +837,18 @@ export default function TemplateDetails({ isWorkspaceContext = false }: Template
|
||||
{/* Workflow preview */}
|
||||
<div className='flex-1 p-6'>
|
||||
<div className='mx-auto max-w-7xl'>
|
||||
<h2 className='mb-4 font-semibold text-xl'>Workflow Preview</h2>
|
||||
<h2 className='mb-4 font-semibold text-[#0D0D0D] text-lg dark:text-[#F0F0F0]'>
|
||||
Workflow Preview
|
||||
</h2>
|
||||
<div className='h-[600px] w-full'>{renderWorkflowPreview()}</div>
|
||||
|
||||
{Array.isArray(template.requiredCredentials) &&
|
||||
template.requiredCredentials.length > 0 && (
|
||||
<div className='mt-8'>
|
||||
<h3 className='mb-3 font-semibold text-lg'>Credentials Needed</h3>
|
||||
<ul className='list-disc space-y-1 pl-6 text-muted-foreground text-sm'>
|
||||
<div className='mt-8 border-t pt-8'>
|
||||
<h3 className='mb-4 font-semibold text-[#0D0D0D] text-base dark:text-[#F0F0F0]'>
|
||||
Credentials Needed
|
||||
</h3>
|
||||
<ul className='ml-5 list-disc space-y-1.5 text-[#707070] text-sm leading-[1.4rem] dark:text-[#E8E8E8]'>
|
||||
{template.requiredCredentials.map((cred: CredentialRequirement, idx: number) => {
|
||||
// Get block name from registry or format blockType
|
||||
const blockName =
|
||||
@@ -862,97 +866,170 @@ export default function TemplateDetails({ isWorkspaceContext = false }: Template
|
||||
|
||||
{/* About this Workflow */}
|
||||
{template.details?.about && (
|
||||
<div className='mt-8'>
|
||||
<h3 className='mb-3 font-semibold text-lg'>About this Workflow</h3>
|
||||
<div className='prose prose-sm dark:prose-invert max-w-none'>
|
||||
<ReactMarkdown>{template.details.about}</ReactMarkdown>
|
||||
<div className='mt-8 border-t pt-8'>
|
||||
<h3 className='mb-4 font-semibold text-[#0D0D0D] text-base dark:text-[#F0F0F0]'>
|
||||
About this Workflow
|
||||
</h3>
|
||||
<div className='max-w-none space-y-2'>
|
||||
<ReactMarkdown
|
||||
components={{
|
||||
p: ({ children }) => (
|
||||
<p className='mb-2 text-[#707070] text-sm leading-[1.4rem] last:mb-0 dark:text-[#E8E8E8]'>
|
||||
{children}
|
||||
</p>
|
||||
),
|
||||
h1: ({ children }) => (
|
||||
<h1 className='mt-6 mb-3 font-semibold text-[#0D0D0D] text-xl first:mt-0 dark:text-[#F0F0F0]'>
|
||||
{children}
|
||||
</h1>
|
||||
),
|
||||
h2: ({ children }) => (
|
||||
<h2 className='mt-5 mb-2.5 font-semibold text-[#0D0D0D] text-lg first:mt-0 dark:text-[#F0F0F0]'>
|
||||
{children}
|
||||
</h2>
|
||||
),
|
||||
h3: ({ children }) => (
|
||||
<h3 className='mt-4 mb-2 font-semibold text-[#0D0D0D] text-base first:mt-0 dark:text-[#F0F0F0]'>
|
||||
{children}
|
||||
</h3>
|
||||
),
|
||||
h4: ({ children }) => (
|
||||
<h4 className='mt-3 mb-2 font-semibold text-[#0D0D0D] text-sm first:mt-0 dark:text-[#F0F0F0]'>
|
||||
{children}
|
||||
</h4>
|
||||
),
|
||||
ul: ({ children }) => (
|
||||
<ul className='my-2 ml-5 list-disc space-y-1.5 text-[#707070] text-sm dark:text-[#E8E8E8]'>
|
||||
{children}
|
||||
</ul>
|
||||
),
|
||||
ol: ({ children }) => (
|
||||
<ol className='my-2 ml-5 list-decimal space-y-1.5 text-[#707070] text-sm dark:text-[#E8E8E8]'>
|
||||
{children}
|
||||
</ol>
|
||||
),
|
||||
li: ({ children }) => <li className='leading-[1.4rem]'>{children}</li>,
|
||||
code: ({ inline, children }: any) =>
|
||||
inline ? (
|
||||
<code className='rounded bg-[#F5F5F5] px-1.5 py-0.5 font-mono text-[#F59E0B] text-xs dark:bg-[#2A2A2A]'>
|
||||
{children}
|
||||
</code>
|
||||
) : (
|
||||
<code className='my-2 block overflow-x-auto rounded-md bg-[#F5F5F5] p-3 font-mono text-[#0D0D0D] text-xs dark:bg-[#1A1A1A] dark:text-[#E5E5E5]'>
|
||||
{children}
|
||||
</code>
|
||||
),
|
||||
a: ({ href, children }) => (
|
||||
<a
|
||||
href={href}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='text-[#3B82F6] underline-offset-2 transition-colors hover:text-[#60A5FA] hover:underline dark:text-[#60A5FA] dark:hover:text-[#93C5FD]'
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
),
|
||||
strong: ({ children }) => (
|
||||
<strong className='font-semibold text-[#0D0D0D] dark:text-white'>
|
||||
{children}
|
||||
</strong>
|
||||
),
|
||||
em: ({ children }) => (
|
||||
<em className='text-[#888888] dark:text-[#B8B8B8]'>{children}</em>
|
||||
),
|
||||
}}
|
||||
>
|
||||
{template.details.about}
|
||||
</ReactMarkdown>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Creator Profile */}
|
||||
{template.creator && (
|
||||
<div className='mt-8'>
|
||||
<h3 className='mb-4 font-semibold text-lg'>About the Creator</h3>
|
||||
<div className='rounded-lg border bg-card p-6'>
|
||||
<div className='flex items-start gap-4'>
|
||||
{/* Profile Picture */}
|
||||
<div className='flex-shrink-0'>
|
||||
{template.creator.profileImageUrl ? (
|
||||
<div className='relative h-20 w-20 overflow-hidden rounded-full'>
|
||||
<img
|
||||
src={template.creator.profileImageUrl}
|
||||
alt={template.creator.name}
|
||||
className='h-full w-full object-cover'
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className='flex h-20 w-20 items-center justify-center rounded-full bg-[#802FFF]'>
|
||||
<User className='h-10 w-10 text-white' />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className='mt-8 border-t pt-8'>
|
||||
<h3 className='mb-4 font-semibold text-[#0D0D0D] text-base dark:text-[#F0F0F0]'>
|
||||
About the Creator
|
||||
</h3>
|
||||
<div className='flex items-start gap-4'>
|
||||
{/* Profile Picture */}
|
||||
<div className='flex-shrink-0'>
|
||||
{template.creator.profileImageUrl ? (
|
||||
<div className='relative h-16 w-16 overflow-hidden rounded-full ring-1 ring-border'>
|
||||
<img
|
||||
src={template.creator.profileImageUrl}
|
||||
alt={template.creator.name}
|
||||
className='h-full w-full object-cover'
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className='flex h-16 w-16 items-center justify-center rounded-full bg-purple-600 ring-1 ring-border'>
|
||||
<User className='h-8 w-8 text-white' />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Creator Info */}
|
||||
<div className='flex-1'>
|
||||
<h4 className='font-semibold text-lg'>{template.creator.name}</h4>
|
||||
{template.creator.details?.about && (
|
||||
<p className='mt-2 text-muted-foreground text-sm leading-relaxed'>
|
||||
{template.creator.details.about}
|
||||
</p>
|
||||
)}
|
||||
{/* Creator Info */}
|
||||
<div className='min-w-0 flex-1'>
|
||||
<h4 className='font-semibold text-[#0D0D0D] dark:text-[#F0F0F0]'>
|
||||
{template.creator.name}
|
||||
</h4>
|
||||
{template.creator.details?.about && (
|
||||
<p className='mt-1.5 text-[#707070] text-sm leading-[1.4rem] dark:text-[#E8E8E8]'>
|
||||
{template.creator.details.about}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{/* Social Links */}
|
||||
{(template.creator.details?.xUrl ||
|
||||
template.creator.details?.linkedinUrl ||
|
||||
template.creator.details?.websiteUrl ||
|
||||
template.creator.details?.contactEmail) && (
|
||||
<div className='mt-4 flex flex-wrap gap-3'>
|
||||
{template.creator.details.xUrl && (
|
||||
<a
|
||||
href={template.creator.details.xUrl}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='inline-flex items-center gap-1.5 text-muted-foreground text-sm transition-colors hover:text-foreground'
|
||||
>
|
||||
<Twitter className='h-4 w-4' />
|
||||
<span>X</span>
|
||||
</a>
|
||||
)}
|
||||
{template.creator.details.linkedinUrl && (
|
||||
<a
|
||||
href={template.creator.details.linkedinUrl}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='inline-flex items-center gap-1.5 text-muted-foreground text-sm transition-colors hover:text-foreground'
|
||||
>
|
||||
<Linkedin className='h-4 w-4' />
|
||||
<span>LinkedIn</span>
|
||||
</a>
|
||||
)}
|
||||
{template.creator.details.websiteUrl && (
|
||||
<a
|
||||
href={template.creator.details.websiteUrl}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='inline-flex items-center gap-1.5 text-muted-foreground text-sm transition-colors hover:text-foreground'
|
||||
>
|
||||
<Globe className='h-4 w-4' />
|
||||
<span>Website</span>
|
||||
</a>
|
||||
)}
|
||||
{template.creator.details.contactEmail && (
|
||||
<a
|
||||
href={`mailto:${template.creator.details.contactEmail}`}
|
||||
className='inline-flex items-center gap-1.5 text-muted-foreground text-sm transition-colors hover:text-foreground'
|
||||
>
|
||||
<Mail className='h-4 w-4' />
|
||||
<span>Contact</span>
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{/* Social Links */}
|
||||
{(template.creator.details?.xUrl ||
|
||||
template.creator.details?.linkedinUrl ||
|
||||
template.creator.details?.websiteUrl ||
|
||||
template.creator.details?.contactEmail) && (
|
||||
<div className='mt-3 flex flex-wrap gap-4'>
|
||||
{template.creator.details.xUrl && (
|
||||
<a
|
||||
href={template.creator.details.xUrl}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='inline-flex items-center gap-1.5 text-[#707070] text-sm transition-colors hover:text-[#0D0D0D] dark:text-[#E8E8E8] dark:hover:text-[#F0F0F0]'
|
||||
>
|
||||
<Twitter className='h-3.5 w-3.5' />
|
||||
<span>X</span>
|
||||
</a>
|
||||
)}
|
||||
{template.creator.details.linkedinUrl && (
|
||||
<a
|
||||
href={template.creator.details.linkedinUrl}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='inline-flex items-center gap-1.5 text-[#707070] text-sm transition-colors hover:text-[#0D0D0D] dark:text-[#E8E8E8] dark:hover:text-[#F0F0F0]'
|
||||
>
|
||||
<Linkedin className='h-3.5 w-3.5' />
|
||||
<span>LinkedIn</span>
|
||||
</a>
|
||||
)}
|
||||
{template.creator.details.websiteUrl && (
|
||||
<a
|
||||
href={template.creator.details.websiteUrl}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='inline-flex items-center gap-1.5 text-[#707070] text-sm transition-colors hover:text-[#0D0D0D] dark:text-[#E8E8E8] dark:hover:text-[#F0F0F0]'
|
||||
>
|
||||
<Globe className='h-3.5 w-3.5' />
|
||||
<span>Website</span>
|
||||
</a>
|
||||
)}
|
||||
{template.creator.details.contactEmail && (
|
||||
<a
|
||||
href={`mailto:${template.creator.details.contactEmail}`}
|
||||
className='inline-flex items-center gap-1.5 text-[#707070] text-sm transition-colors hover:text-[#0D0D0D] dark:text-[#E8E8E8] dark:hover:text-[#F0F0F0]'
|
||||
>
|
||||
<Mail className='h-3.5 w-3.5' />
|
||||
<span>Contact</span>
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -337,8 +337,8 @@ export function TemplateCard({
|
||||
className={cn(
|
||||
'h-4 w-4 cursor-pointer transition-colors duration-50',
|
||||
localIsStarred
|
||||
? 'fill-yellow-400 text-yellow-400'
|
||||
: 'text-muted-foreground hover:fill-yellow-400 hover:text-yellow-400',
|
||||
? 'fill-yellow-500 text-yellow-500'
|
||||
: 'text-muted-foreground hover:fill-yellow-500 hover:text-yellow-500',
|
||||
isStarLoading && 'opacity-50'
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -460,8 +460,8 @@ export function TemplateCard({
|
||||
className={cn(
|
||||
'h-4 w-4 cursor-pointer transition-colors duration-50',
|
||||
localIsStarred
|
||||
? 'fill-yellow-400 text-yellow-400'
|
||||
: 'text-muted-foreground hover:fill-yellow-400 hover:text-yellow-400',
|
||||
? 'fill-yellow-500 text-yellow-500'
|
||||
: 'text-muted-foreground hover:fill-yellow-500 hover:text-yellow-500',
|
||||
isStarLoading && 'opacity-50'
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -7,24 +7,25 @@ import { ThemeProvider as NextThemesProvider } from 'next-themes'
|
||||
export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
|
||||
const pathname = usePathname()
|
||||
|
||||
// Force dark mode for workspace pages
|
||||
// Force dark mode for workspace pages and templates
|
||||
// Force light mode for certain public pages
|
||||
const forcedTheme = pathname.startsWith('/workspace')
|
||||
? 'dark'
|
||||
: pathname === '/' ||
|
||||
pathname.startsWith('/login') ||
|
||||
pathname.startsWith('/signup') ||
|
||||
pathname.startsWith('/sso') ||
|
||||
pathname.startsWith('/terms') ||
|
||||
pathname.startsWith('/privacy') ||
|
||||
pathname.startsWith('/invite') ||
|
||||
pathname.startsWith('/verify') ||
|
||||
pathname.startsWith('/careers') ||
|
||||
pathname.startsWith('/changelog') ||
|
||||
pathname.startsWith('/chat') ||
|
||||
pathname.startsWith('/studio')
|
||||
? 'light'
|
||||
: undefined
|
||||
const forcedTheme =
|
||||
pathname.startsWith('/workspace') || pathname.startsWith('/templates')
|
||||
? 'dark'
|
||||
: pathname === '/' ||
|
||||
pathname.startsWith('/login') ||
|
||||
pathname.startsWith('/signup') ||
|
||||
pathname.startsWith('/sso') ||
|
||||
pathname.startsWith('/terms') ||
|
||||
pathname.startsWith('/privacy') ||
|
||||
pathname.startsWith('/invite') ||
|
||||
pathname.startsWith('/verify') ||
|
||||
pathname.startsWith('/careers') ||
|
||||
pathname.startsWith('/changelog') ||
|
||||
pathname.startsWith('/chat') ||
|
||||
pathname.startsWith('/studio')
|
||||
? 'light'
|
||||
: undefined
|
||||
|
||||
return (
|
||||
<NextThemesProvider
|
||||
|
||||
@@ -353,7 +353,7 @@ export function TemplateCard({
|
||||
onClick={handleStarClick}
|
||||
className={cn(
|
||||
'h-[12px] w-[12px] cursor-pointer transition-colors',
|
||||
localIsStarred ? 'fill-yellow-400 text-yellow-400' : 'text-[#888888]',
|
||||
localIsStarred ? 'fill-yellow-500 text-yellow-500' : 'text-[#888888]',
|
||||
isStarLoading && 'opacity-50'
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -78,33 +78,66 @@ export function TemplateDeploy({ workflowId, onDeploymentComplete }: TemplateDep
|
||||
})
|
||||
|
||||
// Fetch creator profiles
|
||||
useEffect(() => {
|
||||
const fetchCreatorOptions = async () => {
|
||||
if (!session?.user?.id) return
|
||||
const fetchCreatorOptions = async () => {
|
||||
if (!session?.user?.id) return
|
||||
|
||||
setLoadingCreators(true)
|
||||
try {
|
||||
const response = await fetch('/api/creator-profiles')
|
||||
if (response.ok) {
|
||||
const data = await response.json()
|
||||
const profiles = (data.profiles || []).map((profile: any) => ({
|
||||
id: profile.id,
|
||||
name: profile.name,
|
||||
referenceType: profile.referenceType,
|
||||
referenceId: profile.referenceId,
|
||||
}))
|
||||
setCreatorOptions(profiles)
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Error fetching creator profiles:', error)
|
||||
} finally {
|
||||
setLoadingCreators(false)
|
||||
setLoadingCreators(true)
|
||||
try {
|
||||
const response = await fetch('/api/creator-profiles')
|
||||
if (response.ok) {
|
||||
const data = await response.json()
|
||||
const profiles = (data.profiles || []).map((profile: any) => ({
|
||||
id: profile.id,
|
||||
name: profile.name,
|
||||
referenceType: profile.referenceType,
|
||||
referenceId: profile.referenceId,
|
||||
}))
|
||||
setCreatorOptions(profiles)
|
||||
return profiles
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Error fetching creator profiles:', error)
|
||||
} finally {
|
||||
setLoadingCreators(false)
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
fetchCreatorOptions()
|
||||
}, [session?.user?.id])
|
||||
|
||||
// Auto-select creator profile when there's only one option and no selection yet
|
||||
useEffect(() => {
|
||||
const currentCreatorId = form.getValues('creatorId')
|
||||
if (creatorOptions.length === 1 && !currentCreatorId) {
|
||||
form.setValue('creatorId', creatorOptions[0].id)
|
||||
logger.info('Auto-selected single creator profile:', creatorOptions[0].name)
|
||||
}
|
||||
}, [creatorOptions, form])
|
||||
|
||||
// Listen for creator profile saved event
|
||||
useEffect(() => {
|
||||
const handleCreatorProfileSaved = async () => {
|
||||
logger.info('Creator profile saved, refreshing profiles...')
|
||||
|
||||
// Refetch creator profiles (autoselection will happen via the effect above)
|
||||
await fetchCreatorOptions()
|
||||
|
||||
// Close settings modal and reopen deploy modal to template tab
|
||||
window.dispatchEvent(new CustomEvent('close-settings'))
|
||||
setTimeout(() => {
|
||||
window.dispatchEvent(new CustomEvent('open-deploy-modal', { detail: { tab: 'template' } }))
|
||||
}, 100)
|
||||
}
|
||||
|
||||
window.addEventListener('creator-profile-saved', handleCreatorProfileSaved)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('creator-profile-saved', handleCreatorProfileSaved)
|
||||
}
|
||||
}, [])
|
||||
|
||||
// Check for existing template
|
||||
useEffect(() => {
|
||||
const checkExistingTemplate = async () => {
|
||||
@@ -454,12 +487,12 @@ export function TemplateDeploy({ workflowId, onDeploymentComplete }: TemplateDep
|
||||
)}
|
||||
|
||||
{/* Template State Preview Dialog */}
|
||||
{showPreviewDialog && (
|
||||
<Dialog open={showPreviewDialog} onOpenChange={setShowPreviewDialog}>
|
||||
<DialogContent className='max-h-[80vh] max-w-5xl overflow-auto'>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Template State Preview</DialogTitle>
|
||||
</DialogHeader>
|
||||
<Dialog open={showPreviewDialog} onOpenChange={setShowPreviewDialog}>
|
||||
<DialogContent className='max-h-[80vh] max-w-5xl overflow-auto'>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Published Template Preview</DialogTitle>
|
||||
</DialogHeader>
|
||||
{showPreviewDialog && (
|
||||
<div className='mt-4'>
|
||||
{(() => {
|
||||
if (!existingTemplate?.state || !existingTemplate.state.blocks) {
|
||||
@@ -487,7 +520,7 @@ export function TemplateDeploy({ workflowId, onDeploymentComplete }: TemplateDep
|
||||
return (
|
||||
<div className='h-[500px] w-full'>
|
||||
<WorkflowPreview
|
||||
key={`template-preview-${existingTemplate.id}-${Date.now()}`}
|
||||
key={`template-preview-${existingTemplate.id}`}
|
||||
workflowState={workflowState}
|
||||
showSubBlocks={true}
|
||||
height='100%'
|
||||
@@ -497,9 +530,9 @@ export function TemplateDeploy({ workflowId, onDeploymentComplete }: TemplateDep
|
||||
)
|
||||
})()}
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
)}
|
||||
)}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -445,6 +445,23 @@ export function DeployModal({
|
||||
}
|
||||
}, [open, selectedStreamingOutputs, setSelectedStreamingOutputs])
|
||||
|
||||
// Listen for event to reopen deploy modal
|
||||
useEffect(() => {
|
||||
const handleOpenDeployModal = (event: Event) => {
|
||||
const customEvent = event as CustomEvent<{ tab?: TabView }>
|
||||
onOpenChange(true)
|
||||
if (customEvent.detail?.tab) {
|
||||
setActiveTab(customEvent.detail.tab)
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('open-deploy-modal', handleOpenDeployModal)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('open-deploy-modal', handleOpenDeployModal)
|
||||
}
|
||||
}, [onOpenChange])
|
||||
|
||||
const handleActivateVersion = (version: number) => {
|
||||
setVersionToActivate(version)
|
||||
setActiveTab('api')
|
||||
|
||||
@@ -196,7 +196,9 @@ export function CreatorProfile() {
|
||||
logger.info('Creator profile saved successfully')
|
||||
setSaveStatus('saved')
|
||||
|
||||
// Reset to idle after 2 seconds
|
||||
// Dispatch event to notify that a creator profile was saved
|
||||
window.dispatchEvent(new CustomEvent('creator-profile-saved'))
|
||||
|
||||
setTimeout(() => {
|
||||
setSaveStatus('idle')
|
||||
}, 2000)
|
||||
|
||||
@@ -90,10 +90,16 @@ export function SettingsModal({ open, onOpenChange }: SettingsModalProps) {
|
||||
onOpenChange(true)
|
||||
}
|
||||
|
||||
const handleCloseSettings = () => {
|
||||
onOpenChange(false)
|
||||
}
|
||||
|
||||
window.addEventListener('open-settings', handleOpenSettings as EventListener)
|
||||
window.addEventListener('close-settings', handleCloseSettings as EventListener)
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('open-settings', handleOpenSettings as EventListener)
|
||||
window.removeEventListener('close-settings', handleCloseSettings as EventListener)
|
||||
}
|
||||
}, [onOpenChange])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user