Skip to content

Commit f4434e3

Browse files
authored
feat: templates, usage indicator, wand, approval, logs, help, settings, deploy template, error UI (#1931)
* templates, usage indicator, wand, approval, ... * fix: build error import isTruthy
1 parent 42e2769 commit f4434e3

File tree

29 files changed

+1502
-1040
lines changed

29 files changed

+1502
-1040
lines changed

apps/sim/app/workspace/[workspaceId]/logs/components/frozen-canvas/frozen-canvas-modal.tsx

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -43,34 +43,45 @@ export function FrozenCanvasModal({
4343
hideCloseButton={true}
4444
>
4545
{/* Header */}
46-
<DialogHeader className='flex flex-row items-center justify-between border-b bg-background p-4'>
47-
<div className='flex items-center gap-3'>
46+
<DialogHeader className='flex flex-row items-center justify-between border-b bg-[var(--surface-1)] p-[16px] dark:border-[var(--border)] dark:bg-[var(--surface-1)]'>
47+
<div className='flex items-center gap-[12px]'>
4848
<div>
49-
<DialogTitle className='font-semibold text-foreground text-lg'>
49+
<DialogTitle className='font-semibold text-[15px] text-[var(--text-primary)] dark:text-[var(--text-primary)]'>
5050
Logged Workflow State
5151
</DialogTitle>
52-
<div className='mt-1 flex items-center gap-2'>
52+
<div className='mt-[4px] flex items-center gap-[8px]'>
5353
{workflowName && (
54-
<span className='text-muted-foreground text-sm'>{workflowName}</span>
54+
<span className='text-[13px] text-[var(--text-secondary)] dark:text-[var(--text-secondary)]'>
55+
{workflowName}
56+
</span>
5557
)}
5658
{trigger && (
57-
<Badge variant='secondary' className='text-xs'>
59+
<Badge variant='secondary' className='text-[12px]'>
5860
{trigger}
5961
</Badge>
6062
)}
61-
<span className='font-mono text-muted-foreground text-xs'>
63+
<span className='font-mono text-[12px] text-[var(--text-secondary)] dark:text-[var(--text-secondary)]'>
6264
{executionId.slice(0, 8)}...
6365
</span>
6466
</div>
6567
</div>
6668
</div>
6769

68-
<div className='flex items-center gap-2'>
69-
<Button variant='ghost' size='sm' onClick={toggleFullscreen} className='h-8 w-8 p-0'>
70-
{isFullscreen ? <Minimize2 className='h-4 w-4' /> : <Maximize2 className='h-4 w-4' />}
70+
<div className='flex items-center gap-[8px]'>
71+
<Button
72+
variant='ghost'
73+
size='sm'
74+
onClick={toggleFullscreen}
75+
className='h-[32px] w-[32px] p-0'
76+
>
77+
{isFullscreen ? (
78+
<Minimize2 className='h-[14px] w-[14px]' />
79+
) : (
80+
<Maximize2 className='h-[14px] w-[14px]' />
81+
)}
7182
</Button>
72-
<Button variant='ghost' size='sm' onClick={onClose} className='h-8 w-8 p-0'>
73-
<X className='h-4 w-4' />
83+
<Button variant='ghost' size='sm' onClick={onClose} className='h-[32px] w-[32px] p-0'>
84+
<X className='h-[14px] w-[14px]' />
7485
</Button>
7586
</div>
7687
</DialogHeader>
@@ -87,8 +98,8 @@ export function FrozenCanvasModal({
8798
</div>
8899

89100
{/* Footer with instructions */}
90-
<div className='border-t bg-background px-6 py-3'>
91-
<div className='text-muted-foreground text-sm'>
101+
<div className='border-t bg-[var(--surface-1)] px-[24px] py-[12px] dark:border-[var(--border)] dark:bg-[var(--surface-1)]'>
102+
<div className='text-[13px] text-[var(--text-secondary)] dark:text-[var(--text-secondary)]'>
92103
Click on blocks to see their input and output data at execution time. This canvas shows
93104
the exact state of the workflow when this execution was captured.
94105
</div>

apps/sim/app/workspace/[workspaceId]/logs/components/frozen-canvas/frozen-canvas.tsx

Lines changed: 101 additions & 73 deletions
Large diffs are not rendered by default.

apps/sim/app/workspace/[workspaceId]/logs/components/sidebar/sidebar.tsx

Lines changed: 122 additions & 81 deletions
Large diffs are not rendered by default.

apps/sim/app/workspace/[workspaceId]/logs/logs.tsx

Lines changed: 61 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ import type { LogsResponse, WorkflowLog } from '@/stores/logs/filters/types'
2020
const logger = createLogger('Logs')
2121
const LOGS_PER_PAGE = 50
2222

23+
/**
24+
* Returns the background color for a trigger type badge.
25+
*
26+
* @param trigger - The trigger type (manual, schedule, webhook, chat, api)
27+
* @returns Hex color code for the trigger type
28+
*/
2329
const getTriggerColor = (trigger: string | null | undefined): string => {
2430
if (!trigger) return '#9ca3af'
2531

@@ -685,14 +691,14 @@ export default function Logs() {
685691
}
686692

687693
return (
688-
<div className='flex h-full min-w-0 flex-col pl-64'>
694+
<div className='fixed inset-0 left-[256px] flex min-w-0 flex-col'>
689695
{/* Add the animation styles */}
690696
<style jsx global>
691697
{selectedRowAnimation}
692698
</style>
693699

694700
<div className='flex min-w-0 flex-1 overflow-hidden'>
695-
<div className='flex flex-1 flex-col overflow-auto p-6'>
701+
<div className='flex flex-1 flex-col p-[24px]'>
696702
<Controls
697703
isRefetching={isRefreshing}
698704
resetToNow={handleRefresh}
@@ -717,62 +723,57 @@ export default function Logs() {
717723
/>
718724

719725
{/* Table container */}
720-
<div className='flex flex-1 flex-col overflow-hidden'>
721-
{/* Table with responsive layout */}
722-
<div className='w-full overflow-x-auto'>
723-
{/* Header */}
724-
<div>
725-
<div className='border-border border-b'>
726-
<div className='grid min-w-[600px] grid-cols-[120px_80px_120px_120px] gap-2 px-2 pb-3 md:grid-cols-[140px_90px_140px_120px] md:gap-3 lg:min-w-0 lg:grid-cols-[160px_100px_160px_120px] lg:gap-4 xl:grid-cols-[160px_100px_160px_120px_120px_100px]'>
727-
<div className='font-[480] font-sans text-[13px] text-muted-foreground leading-normal'>
728-
Time
729-
</div>
730-
<div className='font-[480] font-sans text-[13px] text-muted-foreground leading-normal'>
731-
Status
732-
</div>
733-
<div className='font-[480] font-sans text-[13px] text-muted-foreground leading-normal'>
734-
Workflow
735-
</div>
736-
<div className='font-[480] font-sans text-[13px] text-muted-foreground leading-normal'>
737-
Cost
738-
</div>
739-
<div className='hidden font-[480] font-sans text-[13px] text-muted-foreground leading-normal xl:block'>
740-
Trigger
741-
</div>
726+
<div className='flex flex-1 flex-col overflow-hidden rounded-[8px] border dark:border-[var(--border)]'>
727+
{/* Header */}
728+
<div className='flex-shrink-0 border-b bg-[var(--surface-1)] dark:border-[var(--border)] dark:bg-[var(--surface-1)]'>
729+
<div className='grid min-w-[600px] grid-cols-[120px_80px_120px_120px] gap-[8px] px-[24px] py-[12px] md:grid-cols-[140px_90px_140px_120px] md:gap-[12px] lg:min-w-0 lg:grid-cols-[160px_100px_160px_120px] lg:gap-[16px] xl:grid-cols-[160px_100px_160px_120px_120px_100px]'>
730+
<div className='font-medium text-[13px] text-[var(--text-tertiary)] dark:text-[var(--text-tertiary)]'>
731+
Time
732+
</div>
733+
<div className='font-medium text-[13px] text-[var(--text-tertiary)] dark:text-[var(--text-tertiary)]'>
734+
Status
735+
</div>
736+
<div className='font-medium text-[13px] text-[var(--text-tertiary)] dark:text-[var(--text-tertiary)]'>
737+
Workflow
738+
</div>
739+
<div className='font-medium text-[13px] text-[var(--text-tertiary)] dark:text-[var(--text-tertiary)]'>
740+
Cost
741+
</div>
742+
<div className='hidden font-medium text-[13px] text-[var(--text-tertiary)] xl:block dark:text-[var(--text-tertiary)]'>
743+
Trigger
744+
</div>
742745

743-
<div className='hidden font-[480] font-sans text-[13px] text-muted-foreground leading-normal xl:block'>
744-
Duration
745-
</div>
746-
</div>
746+
<div className='hidden font-medium text-[13px] text-[var(--text-tertiary)] xl:block dark:text-[var(--text-tertiary)]'>
747+
Duration
747748
</div>
748749
</div>
749750
</div>
750751

751752
{/* Table body - scrollable */}
752-
<div className='flex-1 overflow-auto' ref={scrollContainerRef}>
753+
<div className='flex-1 overflow-y-auto overflow-x-hidden' ref={scrollContainerRef}>
753754
{loading && page === 1 ? (
754755
<div className='flex h-full items-center justify-center'>
755-
<div className='flex items-center gap-2 text-muted-foreground'>
756-
<Loader2 className='h-5 w-5 animate-spin' />
757-
<span className='text-sm'>Loading logs...</span>
756+
<div className='flex items-center gap-[8px] text-[var(--text-secondary)] dark:text-[var(--text-secondary)]'>
757+
<Loader2 className='h-[16px] w-[16px] animate-spin' />
758+
<span className='text-[13px]'>Loading logs...</span>
758759
</div>
759760
</div>
760761
) : error ? (
761762
<div className='flex h-full items-center justify-center'>
762-
<div className='flex items-center gap-2 text-destructive'>
763-
<AlertCircle className='h-5 w-5' />
764-
<span className='text-sm'>Error: {error}</span>
763+
<div className='flex items-center gap-[8px] text-[var(--text-error)] dark:text-[var(--text-error)]'>
764+
<AlertCircle className='h-[16px] w-[16px]' />
765+
<span className='text-[13px]'>Error: {error}</span>
765766
</div>
766767
</div>
767768
) : logs.length === 0 ? (
768769
<div className='flex h-full items-center justify-center'>
769-
<div className='flex items-center gap-2 text-muted-foreground'>
770-
<Info className='h-5 w-5' />
771-
<span className='text-sm'>No logs found</span>
770+
<div className='flex items-center gap-[8px] text-[var(--text-secondary)] dark:text-[var(--text-secondary)]'>
771+
<Info className='h-[16px] w-[16px]' />
772+
<span className='text-[13px]'>No logs found</span>
772773
</div>
773774
</div>
774775
) : (
775-
<div className='pb-4'>
776+
<div className='pb-[16px]'>
776777
{logs.map((log) => {
777778
const formattedDate = formatDate(log.createdAt)
778779
const isSelected = selectedLog?.id === log.id
@@ -788,22 +789,19 @@ export default function Logs() {
788789
<div
789790
key={log.id}
790791
ref={isSelected ? selectedRowRef : null}
791-
className={`cursor-pointer border-border border-b transition-all duration-200 ${
792-
isSelected ? 'bg-accent/40' : 'hover:bg-accent/20'
792+
className={`cursor-pointer border-b transition-all duration-200 dark:border-[var(--border)] ${
793+
isSelected ? 'bg-[var(--border)]' : 'hover:bg-[var(--border)]'
793794
}`}
794795
onClick={() => handleLogClick(log)}
795796
>
796-
<div className='grid min-w-[600px] grid-cols-[120px_80px_120px_120px_40px] items-center gap-2 px-2 py-4 md:grid-cols-[140px_90px_140px_120px_40px] md:gap-3 lg:min-w-0 lg:grid-cols-[160px_100px_160px_120px_40px] lg:gap-4 xl:grid-cols-[160px_100px_160px_120px_120px_100px_40px]'>
797+
<div className='grid min-w-[600px] grid-cols-[120px_80px_120px_120px_40px] items-center gap-[8px] px-[24px] py-[12px] md:grid-cols-[140px_90px_140px_120px_40px] md:gap-[12px] lg:min-w-0 lg:grid-cols-[160px_100px_160px_120px_40px] lg:gap-[16px] xl:grid-cols-[160px_100px_160px_120px_120px_100px_40px]'>
797798
{/* Time */}
798799
<div>
799800
<div className='text-[13px]'>
800-
<span className='font-sm text-muted-foreground'>
801+
<span className='text-[var(--text-secondary)] dark:text-[var(--text-secondary)]'>
801802
{formattedDate.compactDate}
802803
</span>
803-
<span
804-
style={{ marginLeft: '8px' }}
805-
className='hidden font-medium sm:inline'
806-
>
804+
<span className='ml-[8px] hidden font-medium sm:inline'>
807805
{formattedDate.compactTime}
808806
</span>
809807
</div>
@@ -813,7 +811,7 @@ export default function Logs() {
813811
<div>
814812
<div
815813
className={cn(
816-
'inline-flex items-center rounded-[8px] px-[6px] py-[2px] font-medium text-xs transition-all duration-200 lg:px-[8px]',
814+
'inline-flex items-center rounded-[8px] px-[8px] py-[2px] font-medium text-[12px] transition-all duration-200',
817815
isError
818816
? 'bg-red-500 text-white'
819817
: isPending
@@ -827,14 +825,14 @@ export default function Logs() {
827825

828826
{/* Workflow */}
829827
<div className='min-w-0'>
830-
<div className='truncate font-medium text-[13px]'>
828+
<div className='truncate font-medium text-[13px] text-[var(--text-primary)] dark:text-[var(--text-primary)]'>
831829
{log.workflow?.name || 'Unknown Workflow'}
832830
</div>
833831
</div>
834832

835833
{/* Cost */}
836834
<div>
837-
<div className='font-medium text-muted-foreground text-xs'>
835+
<div className='font-medium text-[12px] text-[var(--text-secondary)] dark:text-[var(--text-secondary)]'>
838836
{typeof (log as any)?.cost?.total === 'number'
839837
? `$${((log as any).cost.total as number).toFixed(4)}`
840838
: '—'}
@@ -846,7 +844,7 @@ export default function Logs() {
846844
{log.trigger ? (
847845
<div
848846
className={cn(
849-
'inline-flex items-center rounded-[8px] px-[6px] py-[2px] font-medium text-xs transition-all duration-200 lg:px-[8px]',
847+
'inline-flex items-center rounded-[8px] px-[8px] py-[2px] font-medium text-[12px] transition-all duration-200',
850848
log.trigger.toLowerCase() === 'manual'
851849
? 'bg-secondary text-card-foreground'
852850
: 'text-white'
@@ -860,13 +858,15 @@ export default function Logs() {
860858
{log.trigger}
861859
</div>
862860
) : (
863-
<div className='text-muted-foreground text-xs'></div>
861+
<div className='font-medium text-[12px] text-[var(--text-secondary)] dark:text-[var(--text-secondary)]'>
862+
863+
</div>
864864
)}
865865
</div>
866866

867867
{/* Duration */}
868868
<div className='hidden xl:block'>
869-
<div className='text-muted-foreground text-xs'>
869+
<div className='font-medium text-[12px] text-[var(--text-secondary)] dark:text-[var(--text-secondary)]'>
870870
{log.duration || '—'}
871871
</div>
872872
</div>
@@ -878,13 +878,13 @@ export default function Logs() {
878878
(log.workflow?.id || log.workflowId) ? (
879879
<Link
880880
href={`/resume/${log.workflow?.id || log.workflowId}/${log.executionId}`}
881-
className='inline-flex h-7 w-7 items-center justify-center rounded-md border border-primary/60 border-dashed text-primary hover:bg-primary/10'
881+
className='inline-flex h-[28px] w-[28px] items-center justify-center rounded-[8px] border border-primary/60 border-dashed text-primary hover:bg-primary/10'
882882
aria-label='Open resume console'
883883
>
884-
<ArrowUpRight className='h-4 w-4' />
884+
<ArrowUpRight className='h-[14px] w-[14px]' />
885885
</Link>
886886
) : (
887-
<span className='h-7 w-7' />
887+
<span className='h-[28px] w-[28px]' />
888888
)}
889889
</div>
890890
</div>
@@ -894,18 +894,18 @@ export default function Logs() {
894894

895895
{/* Infinite scroll loader */}
896896
{hasMore && (
897-
<div className='flex items-center justify-center py-4'>
897+
<div className='flex items-center justify-center py-[16px]'>
898898
<div
899899
ref={loaderRef}
900-
className='flex items-center gap-2 text-muted-foreground'
900+
className='flex items-center gap-[8px] text-[var(--text-secondary)] dark:text-[var(--text-secondary)]'
901901
>
902902
{isFetchingMore ? (
903903
<>
904-
<Loader2 className='h-4 w-4 animate-spin' />
905-
<span className='text-sm'>Loading more...</span>
904+
<Loader2 className='h-[16px] w-[16px] animate-spin' />
905+
<span className='text-[13px]'>Loading more...</span>
906906
</>
907907
) : (
908-
<span className='text-sm'>Scroll to load more</span>
908+
<span className='text-[13px]'>Scroll to load more</span>
909909
)}
910910
</div>
911911
</div>

apps/sim/app/workspace/[workspaceId]/templates/[id]/page.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,12 @@ export default async function TemplatePage({ params }: TemplatePageProps) {
9090
} catch (error) {
9191
logger.error('Error loading template:', error)
9292
return (
93-
<div className='flex h-screen items-center justify-center'>
93+
<div className='flex h-[100vh] items-center justify-center pl-64'>
9494
<div className='text-center'>
95-
<h1 className='mb-4 font-bold text-2xl'>Error Loading Template</h1>
96-
<p className='text-muted-foreground'>There was an error loading this template.</p>
97-
<p className='mt-2 text-muted-foreground text-sm'>Template ID: {id}</p>
98-
<p className='mt-2 text-red-500 text-xs'>
95+
<h1 className='mb-[14px] font-medium text-[18px]'>Error Loading Template</h1>
96+
<p className='text-[#888888] text-[14px]'>There was an error loading this template.</p>
97+
<p className='mt-[10px] text-[#888888] text-[12px]'>Template ID: {id}</p>
98+
<p className='mt-[10px] text-[12px] text-red-500'>
9999
{error instanceof Error ? error.message : 'Unknown error'}
100100
</p>
101101
</div>

0 commit comments

Comments
 (0)