mirror of
https://github.com/simstudioai/sim.git
synced 2026-02-17 18:02:09 -05:00
improvement(lint): fix react-doctor errors and warnings (#3232)
* improvement(lint): fix react-doctor errors and warnings * remove separators
This commit is contained in:
@@ -59,12 +59,6 @@ body {
|
||||
--content-gap: 1.75rem;
|
||||
}
|
||||
|
||||
/* Remove custom layout variable overrides to fallback to fumadocs defaults */
|
||||
|
||||
/* ============================================
|
||||
Navbar Light Mode Styling
|
||||
============================================ */
|
||||
|
||||
/* Light mode navbar and search styling */
|
||||
:root:not(.dark) nav {
|
||||
background-color: hsla(0, 0%, 96%, 0.85) !important;
|
||||
@@ -88,10 +82,6 @@ body {
|
||||
-webkit-backdrop-filter: blur(25px) saturate(180%) brightness(0.6) !important;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
Custom Sidebar Styling (Turborepo-inspired)
|
||||
============================================ */
|
||||
|
||||
/* Floating sidebar appearance - remove background */
|
||||
[data-sidebar-container],
|
||||
#nd-sidebar {
|
||||
@@ -468,10 +458,6 @@ aside[data-sidebar],
|
||||
writing-mode: horizontal-tb !important;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
Code Block Styling (Improved)
|
||||
============================================ */
|
||||
|
||||
/* Apply Geist Mono to code elements */
|
||||
code,
|
||||
pre,
|
||||
@@ -532,10 +518,6 @@ pre code .line {
|
||||
color: var(--color-fd-primary);
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
TOC (Table of Contents) Styling
|
||||
============================================ */
|
||||
|
||||
/* Remove the thin border-left on nested TOC items (keeps main indicator only) */
|
||||
#nd-toc a[style*="padding-inline-start"] {
|
||||
border-left: none !important;
|
||||
@@ -554,10 +536,6 @@ main article,
|
||||
padding-bottom: 4rem;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
Center and Constrain Main Content Width
|
||||
============================================ */
|
||||
|
||||
/* Main content area - center and constrain like turborepo/raindrop */
|
||||
/* Note: --sidebar-offset and --toc-offset are now applied at #nd-docs-layout level */
|
||||
main[data-main] {
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
'use server'
|
||||
|
||||
import { env } from '@/lib/core/config/env'
|
||||
import { isProd } from '@/lib/core/config/feature-flags'
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ export const LandingNode = React.memo(function LandingNode({ data }: { data: Lan
|
||||
transform: isAnimated ? 'translateY(0) scale(1)' : 'translateY(8px) scale(0.98)',
|
||||
transition:
|
||||
'opacity 0.6s cubic-bezier(0.22, 1, 0.36, 1), transform 0.6s cubic-bezier(0.22, 1, 0.36, 1)',
|
||||
willChange: 'transform, opacity',
|
||||
willChange: isAnimated ? 'auto' : 'transform, opacity',
|
||||
}}
|
||||
>
|
||||
<LandingBlock icon={data.icon} color={data.color} name={data.name} tags={data.tags} />
|
||||
|
||||
@@ -67,7 +67,6 @@ export const LandingEdge = React.memo(function LandingEdge(props: EdgeProps) {
|
||||
strokeLinejoin: 'round',
|
||||
pointerEvents: 'none',
|
||||
animation: `landing-edge-dash-${id} 1s linear infinite`,
|
||||
willChange: 'stroke-dashoffset',
|
||||
...style,
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -754,3 +754,100 @@ input[type="search"]::-ms-clear {
|
||||
text-decoration: none !important;
|
||||
color: inherit !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Respect user's prefers-reduced-motion setting (WCAG 2.3.3)
|
||||
* Disables animations and transitions for users who prefer reduced motion.
|
||||
*/
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
scroll-behavior: auto !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* WandPromptBar status indicator */
|
||||
@keyframes smoke-pulse {
|
||||
0%,
|
||||
100% {
|
||||
transform: scale(0.8);
|
||||
opacity: 0.4;
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.1);
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
.status-indicator {
|
||||
position: relative;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
background-color: hsl(var(--muted-foreground) / 0.5);
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.status-indicator.streaming {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.status-indicator.streaming::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(
|
||||
circle,
|
||||
hsl(var(--primary) / 0.9) 0%,
|
||||
hsl(var(--primary) / 0.4) 60%,
|
||||
transparent 80%
|
||||
);
|
||||
animation: smoke-pulse 1.8s ease-in-out infinite;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.dark .status-indicator.streaming::before {
|
||||
background: #6b7280;
|
||||
opacity: 0.9;
|
||||
animation: smoke-pulse 1.8s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* MessageContainer loading dot */
|
||||
@keyframes growShrink {
|
||||
0%,
|
||||
100% {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
|
||||
.loading-dot {
|
||||
animation: growShrink 1.5s infinite ease-in-out;
|
||||
}
|
||||
|
||||
/* Subflow node z-index and drag-over styles */
|
||||
.workflow-container .react-flow__node-subflowNode {
|
||||
z-index: -1 !important;
|
||||
}
|
||||
|
||||
.workflow-container .react-flow__node-subflowNode:has([data-subflow-selected="true"]) {
|
||||
z-index: 10 !important;
|
||||
}
|
||||
|
||||
.loop-node-drag-over,
|
||||
.parallel-node-drag-over {
|
||||
box-shadow: 0 0 0 1.75px var(--brand-secondary) !important;
|
||||
border-radius: 8px !important;
|
||||
}
|
||||
|
||||
.react-flow__node[data-parent-node-id] .react-flow__handle {
|
||||
z-index: 30;
|
||||
}
|
||||
|
||||
@@ -30,21 +30,6 @@ export const ChatMessageContainer = memo(function ChatMessageContainer({
|
||||
}: ChatMessageContainerProps) {
|
||||
return (
|
||||
<div className='relative flex flex-1 flex-col overflow-hidden bg-white'>
|
||||
<style jsx>{`
|
||||
@keyframes growShrink {
|
||||
0%,
|
||||
100% {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.1);
|
||||
}
|
||||
}
|
||||
.loading-dot {
|
||||
animation: growShrink 1.5s infinite ease-in-out;
|
||||
}
|
||||
`}</style>
|
||||
|
||||
{/* Scrollable Messages Area */}
|
||||
<div
|
||||
ref={messagesContainerRef}
|
||||
|
||||
@@ -71,7 +71,7 @@ export function VoiceInterface({
|
||||
const [state, setState] = useState<'idle' | 'listening' | 'agent_speaking'>('idle')
|
||||
const [isInitialized, setIsInitialized] = useState(false)
|
||||
const [isMuted, setIsMuted] = useState(false)
|
||||
const [audioLevels, setAudioLevels] = useState<number[]>(new Array(200).fill(0))
|
||||
const [audioLevels, setAudioLevels] = useState<number[]>(() => new Array(200).fill(0))
|
||||
const [permissionStatus, setPermissionStatus] = useState<'prompt' | 'granted' | 'denied'>(
|
||||
'prompt'
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { redirect } from 'next/navigation'
|
||||
import { redirect, unstable_rethrow } from 'next/navigation'
|
||||
import { getSession } from '@/lib/auth'
|
||||
import { getWorkspaceFile } from '@/lib/uploads/contexts/workspace'
|
||||
import { verifyWorkspaceMembership } from '@/app/api/workflows/utils'
|
||||
@@ -14,24 +14,27 @@ interface FileViewerPageProps {
|
||||
export default async function FileViewerPage({ params }: FileViewerPageProps) {
|
||||
const { workspaceId, fileId } = await params
|
||||
|
||||
try {
|
||||
const session = await getSession()
|
||||
if (!session?.user?.id) {
|
||||
redirect('/')
|
||||
}
|
||||
const session = await getSession()
|
||||
if (!session?.user?.id) {
|
||||
redirect('/')
|
||||
}
|
||||
|
||||
const hasPermission = await verifyWorkspaceMembership(session.user.id, workspaceId)
|
||||
if (!hasPermission) {
|
||||
redirect(`/workspace/${workspaceId}`)
|
||||
}
|
||||
|
||||
const fileRecord = await getWorkspaceFile(workspaceId, fileId)
|
||||
if (!fileRecord) {
|
||||
redirect(`/workspace/${workspaceId}`)
|
||||
}
|
||||
|
||||
return <FileViewer file={fileRecord} />
|
||||
} catch (error) {
|
||||
const hasPermission = await verifyWorkspaceMembership(session.user.id, workspaceId)
|
||||
if (!hasPermission) {
|
||||
redirect(`/workspace/${workspaceId}`)
|
||||
}
|
||||
|
||||
let fileRecord: Awaited<ReturnType<typeof getWorkspaceFile>>
|
||||
try {
|
||||
fileRecord = await getWorkspaceFile(workspaceId, fileId)
|
||||
} catch (error) {
|
||||
unstable_rethrow(error)
|
||||
redirect(`/workspace/${workspaceId}`)
|
||||
}
|
||||
|
||||
if (!fileRecord) {
|
||||
redirect(`/workspace/${workspaceId}`)
|
||||
}
|
||||
|
||||
return <FileViewer file={fileRecord} />
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { isEqual } from 'lodash'
|
||||
import isEqual from 'lodash/isEqual'
|
||||
import { useReactFlow } from 'reactflow'
|
||||
import { useStoreWithEqualityFn } from 'zustand/traditional'
|
||||
import { Combobox, type ComboboxOption } from '@/components/emcn/components'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { isEqual } from 'lodash'
|
||||
import isEqual from 'lodash/isEqual'
|
||||
import { useStoreWithEqualityFn } from 'zustand/traditional'
|
||||
import { Badge } from '@/components/emcn'
|
||||
import { Combobox, type ComboboxOption } from '@/components/emcn/components'
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { isEqual } from 'lodash'
|
||||
import isEqual from 'lodash/isEqual'
|
||||
import { ChevronDown, ChevronsUpDown, ChevronUp, Plus } from 'lucide-react'
|
||||
import { Button, Popover, PopoverContent, PopoverItem, PopoverTrigger } from '@/components/emcn'
|
||||
import { Trash } from '@/components/emcn/icons/trash'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { type JSX, type MouseEvent, memo, useCallback, useRef, useState } from 'react'
|
||||
import { isEqual } from 'lodash'
|
||||
import isEqual from 'lodash/isEqual'
|
||||
import { AlertTriangle, ArrowLeftRight, ArrowUp, Check, Clipboard } from 'lucide-react'
|
||||
import { Button, Input, Label, Tooltip } from '@/components/emcn/components'
|
||||
import { cn } from '@/lib/core/utils/cn'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { isEqual } from 'lodash'
|
||||
import isEqual from 'lodash/isEqual'
|
||||
import {
|
||||
BookOpen,
|
||||
Check,
|
||||
|
||||
@@ -10,40 +10,6 @@ import { ActionBar } from '@/app/workspace/[workspaceId]/w/[workflowId]/componen
|
||||
import { useCurrentWorkflow } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks'
|
||||
import { usePanelEditorStore } from '@/stores/panel'
|
||||
|
||||
/**
|
||||
* Global styles for subflow nodes (loop and parallel containers).
|
||||
* Includes animations for drag-over states and hover effects.
|
||||
*
|
||||
* @returns Style component with global CSS
|
||||
*/
|
||||
const SubflowNodeStyles: React.FC = () => {
|
||||
return (
|
||||
<style jsx global>{`
|
||||
/* Z-index management for subflow nodes - default behind blocks */
|
||||
.workflow-container .react-flow__node-subflowNode {
|
||||
z-index: -1 !important;
|
||||
}
|
||||
|
||||
/* Selected subflows appear above other subflows but below blocks (z-21) */
|
||||
.workflow-container .react-flow__node-subflowNode:has([data-subflow-selected='true']) {
|
||||
z-index: 10 !important;
|
||||
}
|
||||
|
||||
/* Drag-over states */
|
||||
.loop-node-drag-over,
|
||||
.parallel-node-drag-over {
|
||||
box-shadow: 0 0 0 1.75px var(--brand-secondary) !important;
|
||||
border-radius: 8px !important;
|
||||
}
|
||||
|
||||
/* Handle z-index for nested nodes */
|
||||
.react-flow__node[data-parent-node-id] .react-flow__handle {
|
||||
z-index: 30;
|
||||
}
|
||||
`}</style>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Data structure for subflow nodes (loop and parallel containers)
|
||||
*/
|
||||
@@ -151,133 +117,130 @@ export const SubflowNodeComponent = memo(({ data, id, selected }: NodeProps<Subf
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
<SubflowNodeStyles />
|
||||
<div className='group relative'>
|
||||
<div className='group relative'>
|
||||
<div
|
||||
ref={blockRef}
|
||||
onClick={() => setCurrentBlockId(id)}
|
||||
className={cn(
|
||||
'workflow-drag-handle relative cursor-grab select-none rounded-[8px] border border-[var(--border-1)] [&:active]:cursor-grabbing',
|
||||
'transition-block-bg transition-ring',
|
||||
'z-[20]'
|
||||
)}
|
||||
style={{
|
||||
width: data.width || 500,
|
||||
height: data.height || 300,
|
||||
position: 'relative',
|
||||
overflow: 'visible',
|
||||
pointerEvents: isPreview ? 'none' : 'all',
|
||||
}}
|
||||
data-node-id={id}
|
||||
data-type='subflowNode'
|
||||
data-nesting-level={nestingLevel}
|
||||
data-subflow-selected={isFocused || isSelected || isPreviewSelected}
|
||||
>
|
||||
{!isPreview && (
|
||||
<ActionBar blockId={id} blockType={data.kind} disabled={!userPermissions.canEdit} />
|
||||
)}
|
||||
|
||||
{/* Header Section */}
|
||||
<div
|
||||
ref={blockRef}
|
||||
onClick={() => setCurrentBlockId(id)}
|
||||
className={cn(
|
||||
'workflow-drag-handle relative cursor-grab select-none rounded-[8px] border border-[var(--border-1)] [&:active]:cursor-grabbing',
|
||||
'transition-block-bg transition-ring',
|
||||
'z-[20]'
|
||||
'flex items-center justify-between rounded-t-[8px] border-[var(--border)] border-b bg-[var(--surface-2)] py-[8px] pr-[12px] pl-[8px]'
|
||||
)}
|
||||
style={{
|
||||
width: data.width || 500,
|
||||
height: data.height || 300,
|
||||
position: 'relative',
|
||||
overflow: 'visible',
|
||||
pointerEvents: isPreview ? 'none' : 'all',
|
||||
}}
|
||||
data-node-id={id}
|
||||
data-type='subflowNode'
|
||||
data-nesting-level={nestingLevel}
|
||||
data-subflow-selected={isFocused || isSelected || isPreviewSelected}
|
||||
>
|
||||
{!isPreview && (
|
||||
<ActionBar blockId={id} blockType={data.kind} disabled={!userPermissions.canEdit} />
|
||||
)}
|
||||
|
||||
{/* Header Section */}
|
||||
<div
|
||||
className={cn(
|
||||
'flex items-center justify-between rounded-t-[8px] border-[var(--border)] border-b bg-[var(--surface-2)] py-[8px] pr-[12px] pl-[8px]'
|
||||
)}
|
||||
>
|
||||
<div className='flex min-w-0 flex-1 items-center gap-[10px]'>
|
||||
<div
|
||||
className='flex h-[24px] w-[24px] flex-shrink-0 items-center justify-center rounded-[6px]'
|
||||
style={{ backgroundColor: isEnabled ? blockIconBg : 'gray' }}
|
||||
>
|
||||
<BlockIcon className='h-[16px] w-[16px] text-white' />
|
||||
</div>
|
||||
<span
|
||||
className={cn(
|
||||
'truncate font-medium text-[16px]',
|
||||
!isEnabled && 'text-[var(--text-muted)]'
|
||||
)}
|
||||
title={blockName}
|
||||
>
|
||||
{blockName}
|
||||
</span>
|
||||
</div>
|
||||
<div className='flex items-center gap-1'>
|
||||
{!isEnabled && <Badge variant='gray-secondary'>disabled</Badge>}
|
||||
{isLocked && <Badge variant='gray-secondary'>locked</Badge>}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!isPreview && (
|
||||
<div className='flex min-w-0 flex-1 items-center gap-[10px]'>
|
||||
<div
|
||||
className='absolute right-[8px] bottom-[8px] z-20 flex h-[32px] w-[32px] cursor-se-resize items-center justify-center text-muted-foreground'
|
||||
style={{ pointerEvents: 'auto' }}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div
|
||||
className='h-[calc(100%-50px)] pt-[16px] pr-[80px] pb-[16px] pl-[16px]'
|
||||
data-dragarea='true'
|
||||
style={{
|
||||
position: 'relative',
|
||||
pointerEvents: isPreview ? 'none' : 'auto',
|
||||
}}
|
||||
>
|
||||
{/* Subflow Start */}
|
||||
<div
|
||||
className='absolute top-[16px] left-[16px] flex items-center justify-center rounded-[8px] border border-[var(--border-1)] bg-[var(--surface-2)] px-[12px] py-[6px]'
|
||||
style={{ pointerEvents: isPreview ? 'none' : 'auto' }}
|
||||
data-parent-id={id}
|
||||
data-node-role={`${data.kind}-start`}
|
||||
data-extent='parent'
|
||||
className='flex h-[24px] w-[24px] flex-shrink-0 items-center justify-center rounded-[6px]'
|
||||
style={{ backgroundColor: isEnabled ? blockIconBg : 'gray' }}
|
||||
>
|
||||
<span className='font-medium text-[14px] text-[var(--text-primary)]'>Start</span>
|
||||
|
||||
<Handle
|
||||
type='source'
|
||||
position={Position.Right}
|
||||
id={startHandleId}
|
||||
className={getHandleClasses('right')}
|
||||
style={{
|
||||
top: '50%',
|
||||
transform: 'translateY(-50%)',
|
||||
pointerEvents: 'auto',
|
||||
}}
|
||||
data-parent-id={id}
|
||||
/>
|
||||
<BlockIcon className='h-[16px] w-[16px] text-white' />
|
||||
</div>
|
||||
<span
|
||||
className={cn(
|
||||
'truncate font-medium text-[16px]',
|
||||
!isEnabled && 'text-[var(--text-muted)]'
|
||||
)}
|
||||
title={blockName}
|
||||
>
|
||||
{blockName}
|
||||
</span>
|
||||
</div>
|
||||
<div className='flex items-center gap-1'>
|
||||
{!isEnabled && <Badge variant='gray-secondary'>disabled</Badge>}
|
||||
{isLocked && <Badge variant='gray-secondary'>locked</Badge>}
|
||||
</div>
|
||||
|
||||
{/* Input handle on left middle */}
|
||||
<Handle
|
||||
type='target'
|
||||
position={Position.Left}
|
||||
className={getHandleClasses('left')}
|
||||
style={{
|
||||
...getHandleStyle(),
|
||||
pointerEvents: 'auto',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Output handle on right middle */}
|
||||
<Handle
|
||||
type='source'
|
||||
position={Position.Right}
|
||||
className={getHandleClasses('right')}
|
||||
style={{
|
||||
...getHandleStyle(),
|
||||
pointerEvents: 'auto',
|
||||
}}
|
||||
id={endHandleId}
|
||||
/>
|
||||
|
||||
{hasRing && (
|
||||
<div
|
||||
className={cn('pointer-events-none absolute inset-0 z-40 rounded-[8px]', ringStyles)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{!isPreview && (
|
||||
<div
|
||||
className='absolute right-[8px] bottom-[8px] z-20 flex h-[32px] w-[32px] cursor-se-resize items-center justify-center text-muted-foreground'
|
||||
style={{ pointerEvents: 'auto' }}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div
|
||||
className='h-[calc(100%-50px)] pt-[16px] pr-[80px] pb-[16px] pl-[16px]'
|
||||
data-dragarea='true'
|
||||
style={{
|
||||
position: 'relative',
|
||||
pointerEvents: isPreview ? 'none' : 'auto',
|
||||
}}
|
||||
>
|
||||
{/* Subflow Start */}
|
||||
<div
|
||||
className='absolute top-[16px] left-[16px] flex items-center justify-center rounded-[8px] border border-[var(--border-1)] bg-[var(--surface-2)] px-[12px] py-[6px]'
|
||||
style={{ pointerEvents: isPreview ? 'none' : 'auto' }}
|
||||
data-parent-id={id}
|
||||
data-node-role={`${data.kind}-start`}
|
||||
data-extent='parent'
|
||||
>
|
||||
<span className='font-medium text-[14px] text-[var(--text-primary)]'>Start</span>
|
||||
|
||||
<Handle
|
||||
type='source'
|
||||
position={Position.Right}
|
||||
id={startHandleId}
|
||||
className={getHandleClasses('right')}
|
||||
style={{
|
||||
top: '50%',
|
||||
transform: 'translateY(-50%)',
|
||||
pointerEvents: 'auto',
|
||||
}}
|
||||
data-parent-id={id}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Input handle on left middle */}
|
||||
<Handle
|
||||
type='target'
|
||||
position={Position.Left}
|
||||
className={getHandleClasses('left')}
|
||||
style={{
|
||||
...getHandleStyle(),
|
||||
pointerEvents: 'auto',
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Output handle on right middle */}
|
||||
<Handle
|
||||
type='source'
|
||||
position={Position.Right}
|
||||
className={getHandleClasses('right')}
|
||||
style={{
|
||||
...getHandleStyle(),
|
||||
pointerEvents: 'auto',
|
||||
}}
|
||||
id={endHandleId}
|
||||
/>
|
||||
|
||||
{hasRing && (
|
||||
<div
|
||||
className={cn('pointer-events-none absolute inset-0 z-40 rounded-[8px]', ringStyles)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
@@ -134,57 +134,6 @@ export function WandPromptBar({
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<style jsx global>{`
|
||||
|
||||
@keyframes smoke-pulse {
|
||||
0%,
|
||||
100% {
|
||||
transform: scale(0.8);
|
||||
opacity: 0.4;
|
||||
}
|
||||
50% {
|
||||
transform: scale(1.1);
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
.status-indicator {
|
||||
position: relative;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
background-color: hsl(var(--muted-foreground) / 0.5);
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.status-indicator.streaming {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.status-indicator.streaming::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(
|
||||
circle,
|
||||
hsl(var(--primary) / 0.9) 0%,
|
||||
hsl(var(--primary) / 0.4) 60%,
|
||||
transparent 80%
|
||||
);
|
||||
animation: smoke-pulse 1.8s ease-in-out infinite;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.dark .status-indicator.streaming::before {
|
||||
background: #6b7280;
|
||||
opacity: 0.9;
|
||||
animation: smoke-pulse 1.8s ease-in-out infinite;
|
||||
}
|
||||
|
||||
`}</style>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { memo, useCallback, useEffect, useMemo, useRef } from 'react'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { isEqual } from 'lodash'
|
||||
import isEqual from 'lodash/isEqual'
|
||||
import { useParams } from 'next/navigation'
|
||||
import { Handle, type NodeProps, Position, useUpdateNodeInternals } from 'reactflow'
|
||||
import { useStoreWithEqualityFn } from 'zustand/traditional'
|
||||
|
||||
@@ -514,6 +514,7 @@ export function HelpModal({ open, onOpenChange, workflowId, workspaceId }: HelpM
|
||||
alt={`Preview ${index + 1}`}
|
||||
fill
|
||||
unoptimized
|
||||
sizes='(max-width: 768px) 100vw, 50vw'
|
||||
className='object-contain'
|
||||
/>
|
||||
<button
|
||||
|
||||
@@ -165,12 +165,16 @@ export function CancelSubscription({ subscription, subscriptionData }: CancelSub
|
||||
logger.info('Subscription restored successfully', result)
|
||||
}
|
||||
|
||||
await queryClient.invalidateQueries({ queryKey: subscriptionKeys.all })
|
||||
if (activeOrgId) {
|
||||
await queryClient.invalidateQueries({ queryKey: organizationKeys.detail(activeOrgId) })
|
||||
await queryClient.invalidateQueries({ queryKey: organizationKeys.billing(activeOrgId) })
|
||||
await queryClient.invalidateQueries({ queryKey: organizationKeys.lists() })
|
||||
}
|
||||
await Promise.all([
|
||||
queryClient.invalidateQueries({ queryKey: subscriptionKeys.all }),
|
||||
...(activeOrgId
|
||||
? [
|
||||
queryClient.invalidateQueries({ queryKey: organizationKeys.detail(activeOrgId) }),
|
||||
queryClient.invalidateQueries({ queryKey: organizationKeys.billing(activeOrgId) }),
|
||||
queryClient.invalidateQueries({ queryKey: organizationKeys.lists() }),
|
||||
]
|
||||
: []),
|
||||
])
|
||||
|
||||
setIsDialogOpen(false)
|
||||
} catch (err) {
|
||||
|
||||
@@ -37,7 +37,7 @@ export const UsageLimit = forwardRef<UsageLimitRef, UsageLimitProps>(
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const [inputValue, setInputValue] = useState(currentLimit.toString())
|
||||
const [inputValue, setInputValue] = useState(() => currentLimit.toString())
|
||||
const [hasError, setHasError] = useState(false)
|
||||
const [errorType, setErrorType] = useState<'general' | 'belowUsage' | null>(null)
|
||||
const [isEditing, setIsEditing] = useState(false)
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
type ReactNode,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useId,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
@@ -170,6 +171,7 @@ const Combobox = memo(
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const listboxId = useId()
|
||||
const [open, setOpen] = useState(false)
|
||||
const [highlightedIndex, setHighlightedIndex] = useState(-1)
|
||||
const [searchQuery, setSearchQuery] = useState('')
|
||||
@@ -513,6 +515,7 @@ const Combobox = memo(
|
||||
role='combobox'
|
||||
aria-expanded={open}
|
||||
aria-haspopup='listbox'
|
||||
aria-controls={listboxId}
|
||||
aria-disabled={disabled}
|
||||
tabIndex={disabled ? -1 : 0}
|
||||
className={cn(
|
||||
@@ -616,7 +619,7 @@ const Combobox = memo(
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div ref={dropdownRef} role='listbox'>
|
||||
<div ref={dropdownRef} role='listbox' id={listboxId}>
|
||||
{isLoading ? (
|
||||
<div className='flex items-center justify-center py-[14px]'>
|
||||
<Loader2 className='h-[16px] w-[16px] animate-spin text-[var(--text-muted)]' />
|
||||
|
||||
@@ -27,12 +27,14 @@ const Alert = React.forwardRef<
|
||||
Alert.displayName = 'Alert'
|
||||
|
||||
const AlertTitle = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLHeadingElement>>(
|
||||
({ className, ...props }, ref) => (
|
||||
({ className, children, ...props }, ref) => (
|
||||
<h5
|
||||
ref={ref}
|
||||
className={cn('mb-1 font-medium leading-none tracking-tight', className)}
|
||||
{...props}
|
||||
/>
|
||||
>
|
||||
{children}
|
||||
</h5>
|
||||
)
|
||||
)
|
||||
AlertTitle.displayName = 'AlertTitle'
|
||||
|
||||
@@ -16,26 +16,32 @@ export const mdxComponents: MDXRemoteProps['components'] = {
|
||||
unoptimized
|
||||
/>
|
||||
),
|
||||
h2: (props: any) => (
|
||||
h2: ({ children, className, ...props }: any) => (
|
||||
<h2
|
||||
{...props}
|
||||
style={{ fontSize: '30px', marginTop: '3rem', marginBottom: '1.5rem' }}
|
||||
className={clsx('font-medium text-black leading-tight', props.className)}
|
||||
/>
|
||||
className={clsx('font-medium text-black leading-tight', className)}
|
||||
>
|
||||
{children}
|
||||
</h2>
|
||||
),
|
||||
h3: (props: any) => (
|
||||
h3: ({ children, className, ...props }: any) => (
|
||||
<h3
|
||||
{...props}
|
||||
style={{ fontSize: '24px', marginTop: '1.5rem', marginBottom: '0.75rem' }}
|
||||
className={clsx('font-medium leading-tight', props.className)}
|
||||
/>
|
||||
className={clsx('font-medium leading-tight', className)}
|
||||
>
|
||||
{children}
|
||||
</h3>
|
||||
),
|
||||
h4: (props: any) => (
|
||||
h4: ({ children, className, ...props }: any) => (
|
||||
<h4
|
||||
{...props}
|
||||
style={{ fontSize: '19px', marginTop: '1.5rem', marginBottom: '0.75rem' }}
|
||||
className={clsx('font-medium leading-tight', props.className)}
|
||||
/>
|
||||
className={clsx('font-medium leading-tight', className)}
|
||||
>
|
||||
{children}
|
||||
</h4>
|
||||
),
|
||||
p: (props: any) => (
|
||||
<p
|
||||
|
||||
@@ -107,5 +107,3 @@ if (typeof process !== 'undefined') {
|
||||
logger.info(`S3 copilot bucket: ${env.S3_COPILOT_BUCKET_NAME}`)
|
||||
}
|
||||
}
|
||||
|
||||
export default ensureUploadsDirectory
|
||||
|
||||
Reference in New Issue
Block a user