Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
ENTERPRISE_PLAN_FEATURES,
PRO_PLAN_FEATURES,
TEAM_PLAN_FEATURES,
} from '@/app/workspace/[workspaceId]/w/components/sidebar/components/settings-modal/components/subscription/plan-configs'
} from '@/app/workspace/[workspaceId]/settings/components/subscription/plan-configs'

const logger = createLogger('LandingPricing')

Expand Down
2 changes: 1 addition & 1 deletion apps/sim/app/api/copilot/chat/stream/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
getStreamMeta,
readStreamEvents,
type StreamMeta,
} from '@/lib/copilot/orchestrator/stream-buffer'
} from '@/lib/copilot/orchestrator/stream/buffer'
import { authenticateCopilotRequestSessionOnly } from '@/lib/copilot/request-helpers'
import { SSE_HEADERS } from '@/lib/core/utils/sse'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,9 @@ describe('Workspace Invitation [invitationId] API Route', () => {
const response = await GET(request, { params })

expect(response.status).toBe(307)
expect(response.headers.get('location')).toBe('https://test.sim.ai/workspace/workspace-456/w')
expect(response.headers.get('location')).toBe(
'https://test.sim.ai/workspace/workspace-456/home'
)
})

it('should redirect to error page with token preserved when invitation expired', async () => {
Expand Down Expand Up @@ -495,7 +497,7 @@ describe('Workspace Invitation [invitationId] API Route', () => {

expect(response2.status).toBe(307)
expect(response2.headers.get('location')).toBe(
'https://test.sim.ai/workspace/workspace-456/w'
'https://test.sim.ai/workspace/workspace-456/home'
)
})
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ export async function GET(
.where(eq(workspaceInvitation.id, invitation.id))

return NextResponse.redirect(
new URL(`/workspace/${invitation.workspaceId}/w`, getBaseUrl())
new URL(`/workspace/${invitation.workspaceId}/home`, getBaseUrl())
)
}

Expand Down Expand Up @@ -193,7 +193,9 @@ export async function GET(
request: req,
})

return NextResponse.redirect(new URL(`/workspace/${invitation.workspaceId}/w`, getBaseUrl()))
return NextResponse.redirect(
new URL(`/workspace/${invitation.workspaceId}/home`, getBaseUrl())
)
}

return NextResponse.json({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ const PLAN_NAMES = {
free: 'Free',
} as const

export function Files() {
export function FileList() {
const params = useParams()
const workspaceId = params?.workspaceId as string

Expand Down Expand Up @@ -227,19 +227,19 @@ export function Files() {
const displayPlanName = PLAN_NAMES[planName as keyof typeof PLAN_NAMES] || 'Free'

const renderTableSkeleton = () => (
<Table className='table-fixed text-[13px]'>
<Table className='table-fixed text-[14px]'>
<TableHeader>
<TableRow className='hover:bg-transparent'>
<TableHead className='w-[56%] px-[12px] py-[8px] text-[12px] text-[var(--text-secondary)]'>
<TableHead className='w-[56%] px-[12px] py-[8px] text-[13px] text-[var(--text-secondary)]'>
<Skeleton className='h-[12px] w-[40px]' />
</TableHead>
<TableHead className='w-[14%] px-[12px] py-[8px] text-left text-[12px] text-[var(--text-secondary)]'>
<TableHead className='w-[14%] px-[12px] py-[8px] text-left text-[13px] text-[var(--text-secondary)]'>
<Skeleton className='h-[12px] w-[28px]' />
</TableHead>
<TableHead className='w-[15%] px-[12px] py-[8px] text-left text-[12px] text-[var(--text-secondary)]'>
<TableHead className='w-[15%] px-[12px] py-[8px] text-left text-[13px] text-[var(--text-secondary)]'>
<Skeleton className='h-[12px] w-[56px]' />
</TableHead>
<TableHead className='w-[15%] px-[12px] py-[8px] text-left text-[12px] text-[var(--text-secondary)]'>
<TableHead className='w-[15%] px-[12px] py-[8px] text-left text-[13px] text-[var(--text-secondary)]'>
<Skeleton className='h-[12px] w-[48px]' />
</TableHead>
</TableRow>
Expand All @@ -253,10 +253,10 @@ export function Files() {
<Skeleton className='h-[14px] w-[180px]' />
</div>
</TableCell>
<TableCell className='whitespace-nowrap px-[12px] py-[8px] text-[12px]'>
<TableCell className='whitespace-nowrap px-[12px] py-[8px] text-[13px]'>
<Skeleton className='h-[12px] w-[48px]' />
</TableCell>
<TableCell className='whitespace-nowrap px-[12px] py-[8px] text-[12px]'>
<TableCell className='whitespace-nowrap px-[12px] py-[8px] text-[13px]'>
<Skeleton className='h-[12px] w-[56px]' />
</TableCell>
<TableCell className='px-[12px] py-[8px]'>
Expand All @@ -272,80 +272,80 @@ export function Files() {
)

return (
<div className='flex h-full flex-col gap-[2px]'>
{/* Search Input and Upload Button */}
<div className='flex items-center gap-[8px]'>
<div className='flex h-full flex-col'>
{/* Search and Actions */}
<div className='mt-[14px] flex items-center justify-between'>
<div
className={cn(
'flex flex-1 items-center gap-[8px] rounded-[8px] border border-[var(--border)] bg-transparent px-[8px] py-[5px] transition-colors duration-100 dark:bg-[var(--surface-4)] dark:hover:border-[var(--border-1)] dark:hover:bg-[var(--surface-5)]',
'flex h-[32px] w-[400px] items-center gap-[6px] rounded-[8px] bg-[var(--surface-4)] px-[8px]',
permissionsLoading && 'opacity-50'
)}
>
<Search
className='h-[14px] w-[14px] flex-shrink-0 text-[var(--text-tertiary)]'
strokeWidth={2}
/>
<Search className='h-[14px] w-[14px] text-[var(--text-subtle)]' />
<Input
placeholder='Search files...'
placeholder='Search'
value={search}
onChange={(e) => setSearch(e.target.value)}
disabled={permissionsLoading}
className='h-auto flex-1 border-0 bg-transparent p-0 font-base leading-none placeholder:text-[var(--text-tertiary)] focus-visible:ring-0 focus-visible:ring-offset-0 disabled:cursor-not-allowed disabled:opacity-100'
className='flex-1 border-0 bg-transparent px-0 font-medium text-[var(--text-secondary)] text-small leading-none placeholder:text-[var(--text-subtle)] focus-visible:ring-0 focus-visible:ring-offset-0 disabled:cursor-not-allowed disabled:opacity-100'
/>
</div>
{(permissionsLoading || userPermissions.canEdit) && (
<>
<input
ref={fileInputRef}
type='file'
className='hidden'
onChange={handleFileChange}
disabled={uploading || permissionsLoading}
accept={ACCEPT_ATTR}
multiple
/>
<Button
onClick={handleUploadClick}
disabled={uploading || permissionsLoading}
variant='tertiary'
>
<Plus className='mr-[6px] h-[13px] w-[13px]' />
{uploading && uploadProgress.total > 0
? `${uploadProgress.completed}/${uploadProgress.total}`
: uploading
? 'Uploading...'
: 'Upload'}
</Button>
</>
)}
<div className='flex items-center gap-[8px]'>
{(permissionsLoading || userPermissions.canEdit) && (
<>
<input
ref={fileInputRef}
type='file'
className='hidden'
onChange={handleFileChange}
disabled={uploading || permissionsLoading}
accept={ACCEPT_ATTR}
multiple
/>
<Button
onClick={handleUploadClick}
disabled={uploading || permissionsLoading}
variant='tertiary'
className='h-[32px] rounded-[6px]'
>
<Plus className='mr-[6px] h-[14px] w-[14px]' />
{uploading && uploadProgress.total > 0
? `${uploadProgress.completed}/${uploadProgress.total}`
: uploading
? 'Uploading...'
: 'Upload'}
</Button>
</>
)}
</div>
</div>

{/* Scrollable Content */}
<div ref={scrollContainerRef} className='min-h-0 flex-1 overflow-y-auto'>
{/* Content */}
<div ref={scrollContainerRef} className='mt-[24px] min-h-0 flex-1 overflow-y-auto'>
{permissionsLoading ? (
renderTableSkeleton()
) : files.length === 0 && failedFiles.length === 0 ? (
<div className='flex h-full items-center justify-center text-[13px] text-[var(--text-muted)]'>
<div className='flex h-full items-center justify-center text-[14px] text-[var(--text-muted)]'>
No files uploaded yet
</div>
) : filteredFiles.length === 0 && failedFiles.length === 0 ? (
<div className='py-[16px] text-center text-[13px] text-[var(--text-muted)]'>
<div className='py-[16px] text-center text-[14px] text-[var(--text-muted)]'>
No files found matching "{search}"
</div>
) : (
<Table className='table-fixed text-[13px]'>
<Table className='table-fixed text-[14px]'>
<TableHeader>
<TableRow className='hover:bg-transparent'>
<TableHead className='w-[56%] px-[12px] py-[8px] text-[12px] text-[var(--text-secondary)]'>
<TableHead className='w-[56%] px-[12px] py-[8px] text-[13px] text-[var(--text-secondary)]'>
Name
</TableHead>
<TableHead className='w-[14%] px-[12px] py-[8px] text-left text-[12px] text-[var(--text-secondary)]'>
<TableHead className='w-[14%] px-[12px] py-[8px] text-left text-[13px] text-[var(--text-secondary)]'>
Size
</TableHead>
<TableHead className='w-[15%] px-[12px] py-[8px] text-left text-[12px] text-[var(--text-secondary)]'>
<TableHead className='w-[15%] px-[12px] py-[8px] text-left text-[13px] text-[var(--text-secondary)]'>
Uploaded
</TableHead>
<TableHead className='w-[15%] px-[12px] py-[8px] text-left text-[12px] text-[var(--text-secondary)]'>
<TableHead className='w-[15%] px-[12px] py-[8px] text-left text-[13px] text-[var(--text-secondary)]'>
Actions
</TableHead>
</TableRow>
Expand All @@ -362,17 +362,17 @@ export function Files() {
<div className='flex min-w-0 items-center gap-[8px]'>
<Icon className='h-[14px] w-[14px] shrink-0 text-[var(--text-error)]' />
<span
className='min-w-0 truncate text-[14px] text-[var(--text-error)]'
className='min-w-0 truncate text-[15px] text-[var(--text-error)]'
title={fileName}
>
{truncateMiddle(fileName)}
</span>
</div>
</TableCell>
<TableCell className='whitespace-nowrap px-[12px] py-[8px] text-[12px] text-[var(--text-error)]'>
<TableCell className='whitespace-nowrap px-[12px] py-[8px] text-[13px] text-[var(--text-error)]'>
</TableCell>
<TableCell className='whitespace-nowrap px-[12px] py-[8px] text-[12px] text-[var(--text-error)]'>
<TableCell className='whitespace-nowrap px-[12px] py-[8px] text-[13px] text-[var(--text-error)]'>
</TableCell>
<TableCell className='px-[12px] py-[8px]'>
Expand All @@ -398,17 +398,17 @@ export function Files() {
<button
onClick={() => handleDownload(file)}
disabled={downloadingFileId === file.id}
className='min-w-0 truncate text-left font-normal text-[14px] text-[var(--text-primary)] hover:underline disabled:cursor-not-allowed disabled:no-underline disabled:opacity-50'
className='min-w-0 truncate text-left font-normal text-[15px] text-[var(--text-primary)] hover:underline disabled:cursor-not-allowed disabled:no-underline disabled:opacity-50'
title={file.name}
>
{truncateMiddle(file.name)}
</button>
</div>
</TableCell>
<TableCell className='whitespace-nowrap px-[12px] py-[8px] text-[12px] text-[var(--text-muted)]'>
<TableCell className='whitespace-nowrap px-[12px] py-[8px] text-[13px] text-[var(--text-muted)]'>
{formatFileSize(file.size)}
</TableCell>
<TableCell className='whitespace-nowrap px-[12px] py-[8px] text-[12px] text-[var(--text-muted)]'>
<TableCell className='whitespace-nowrap px-[12px] py-[8px] text-[13px] text-[var(--text-muted)]'>
{formatDate(file.uploadedAt)}
</TableCell>
<TableCell className='px-[12px] py-[8px]'>
Expand Down Expand Up @@ -467,7 +467,7 @@ export function Files() {
<div className='h-[14px] w-[1.5px] bg-[var(--divider)]' />
<div className='flex items-center gap-[4px]'>
<Skeleton className='h-[12px] w-[40px] rounded-[2px]' />
<span className='font-medium text-[12px] text-[var(--text-tertiary)]'>/</span>
<span className='font-medium text-[13px] text-[var(--text-tertiary)]'>/</span>
<Skeleton className='h-[12px] w-[32px] rounded-[2px]' />
</div>
</div>
Expand All @@ -483,16 +483,16 @@ export function Files() {
<div className='mt-auto flex flex-col gap-[8px] pt-[10px]'>
<div className='flex items-center justify-between'>
<div className='flex items-center gap-[6px]'>
<span className='font-medium text-[12px] text-[var(--text-primary)]'>
<span className='font-medium text-[13px] text-[var(--text-primary)]'>
{displayPlanName}
</span>
<div className='h-[14px] w-[1.5px] bg-[var(--divider)]' />
<div className='flex items-center gap-[4px]'>
<span className='font-medium text-[12px] text-[var(--text-tertiary)] tabular-nums'>
<span className='font-medium text-[13px] text-[var(--text-tertiary)] tabular-nums'>
{formatStorageSize(storageInfo.usedBytes)}
</span>
<span className='font-medium text-[12px] text-[var(--text-tertiary)]'>/</span>
<span className='font-medium text-[12px] text-[var(--text-tertiary)] tabular-nums'>
<span className='font-medium text-[13px] text-[var(--text-tertiary)]'>/</span>
<span className='font-medium text-[13px] text-[var(--text-tertiary)] tabular-nums'>
{formatStorageSize(storageInfo.limitBytes)}
</span>
</div>
Expand Down
25 changes: 0 additions & 25 deletions apps/sim/app/workspace/[workspaceId]/files/files-view.tsx

This file was deleted.

30 changes: 30 additions & 0 deletions apps/sim/app/workspace/[workspaceId]/files/files.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use client'

import { Files as FilesIcon } from 'lucide-react'
import { FileList } from '@/app/workspace/[workspaceId]/files/components/file-list'

export function Files() {
return (
<div className='flex h-full flex-1 flex-col'>
<div className='flex flex-1 overflow-hidden'>
<div className='flex flex-1 flex-col overflow-auto bg-white px-[24px] pt-[28px] pb-[24px] dark:bg-[var(--bg)]'>
{/* Header */}
<div>
Comment on lines +10 to +12
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded bg-white bypasses theme CSS variable

The inner container uses bg-white for light mode rather than a CSS variable (--bg or --surface-2). If the theme defines a non-white light background (e.g. in a white-label config), this element will appear inconsistent with the rest of the UI. The dark mode counterpart already uses dark:bg-[var(--bg)] correctly.

Suggested change
<div className='flex flex-1 flex-col overflow-auto bg-white px-[24px] pt-[28px] pb-[24px] dark:bg-[var(--bg)]'>
{/* Header */}
<div>
<div className='flex flex-1 flex-col overflow-auto bg-[var(--bg)] px-[24px] pt-[28px] pb-[24px]'>

<div className='flex items-start gap-[12px]'>
<div className='flex h-[26px] w-[26px] items-center justify-center rounded-[6px] border border-[#8B5CF6] bg-[#F5F3FF] dark:border-[#5B21B6] dark:bg-[#2E1065]'>
<FilesIcon className='h-[14px] w-[14px] text-[#8B5CF6] dark:text-[#A78BFA]' />
</div>
<h1 className='font-medium text-[18px]'>Files</h1>
</div>
<p className='mt-[10px] text-[14px] text-[var(--text-tertiary)]'>
Workspace files accessible across all workflows.
</p>
</div>

{/* Search, Actions, and Content */}
<FileList />
</div>
</div>
</div>
)
}
4 changes: 2 additions & 2 deletions apps/sim/app/workspace/[workspaceId]/files/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { redirect } from 'next/navigation'
import { getSession } from '@/lib/auth'
import { verifyWorkspaceMembership } from '@/app/api/workflows/utils'
import { getUserPermissionConfig } from '@/ee/access-control/utils/permission-check'
import { FilesView } from './files-view'
import { Files } from './files'

interface FilesPageProps {
params: Promise<{
Expand All @@ -28,5 +28,5 @@ export default async function FilesPage({ params }: FilesPageProps) {
redirect(`/workspace/${workspaceId}`)
}

return <FilesView />
return <Files />
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ export function ActionBar({
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 10 }}
transition={{ duration: 0.2 }}
className={cn('-translate-x-1/2 fixed bottom-6 left-1/2 z-50 transform', className)}
className={cn('-translate-x-1/2 fixed bottom-6 z-50 transform', className)}
style={{ left: 'calc(50% + var(--sidebar-width, 0px) / 2)' }}
>
<div className='flex items-center gap-[8px] rounded-[10px] border border-[var(--border)] bg-[var(--surface-2)] px-[8px] py-[6px]'>
<span className='px-[4px] text-[13px] text-[var(--text-secondary)]'>
Expand Down
2 changes: 1 addition & 1 deletion apps/sim/app/workspace/[workspaceId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ export default async function WorkspacePage({
params: Promise<{ workspaceId: string }>
}) {
const { workspaceId } = await params
redirect(`/workspace/${workspaceId}/w`)
redirect(`/workspace/${workspaceId}/home`)
}
Loading