Skip to content

Commit f3a4053

Browse files
committed
improvements(knowledge): ui/ux
1 parent 1eda44d commit f3a4053

File tree

8 files changed

+158
-97
lines changed

8 files changed

+158
-97
lines changed

apps/sim/app/api/files/presigned/route.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { getSignedUrl } from '@aws-sdk/s3-request-presigner'
33
import { type NextRequest, NextResponse } from 'next/server'
44
import { v4 as uuidv4 } from 'uuid'
55
import { createLogger } from '@/lib/logs/console-logger'
6-
import { getS3Client } from '@/lib/uploads/s3-client'
6+
import { getS3Client, sanitizeFilenameForMetadata } from '@/lib/uploads/s3-client'
77
import { S3_CONFIG, USE_S3_STORAGE } from '@/lib/uploads/setup'
88
import { createErrorResponse, createOptionsResponse } from '../utils'
99

@@ -40,6 +40,9 @@ export async function POST(request: NextRequest) {
4040
const safeFileName = fileName.replace(/\s+/g, '-')
4141
const uniqueKey = `${Date.now()}-${uuidv4()}-${safeFileName}`
4242

43+
// Sanitize the original filename for S3 metadata to prevent header errors
44+
const sanitizedOriginalName = sanitizeFilenameForMetadata(fileName)
45+
4346
// Create the S3 command
4447
const command = new PutObjectCommand({
4548
Bucket: S3_CONFIG.bucket,

apps/sim/app/w/knowledge/[id]/[documentId]/components/document-loading.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export function DocumentLoading({
4747
<div className='flex flex-1 overflow-hidden'>
4848
<div className='flex flex-1 flex-col overflow-hidden'>
4949
{/* Main Content */}
50-
<div className='flex-1 overflow-auto pt-[4px]'>
50+
<div className='flex-1 overflow-auto'>
5151
<div className='px-6 pb-6'>
5252
{/* Search Section */}
5353
<div className='mb-4'>

apps/sim/app/w/knowledge/[id]/base.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,9 @@ export function KnowledgeBase({
649649
<th className='px-4 pt-2 pb-3 text-left font-medium'>
650650
<span className='text-muted-foreground text-xs leading-none'>Status</span>
651651
</th>
652+
<th className='px-4 pt-2 pb-3 text-left font-medium'>
653+
<span className='text-muted-foreground text-xs leading-none'>Status</span>
654+
</th>
652655
<th className='px-4 pt-2 pb-3 text-left font-medium'>
653656
<span className='text-muted-foreground text-xs leading-none'>
654657
Actions
@@ -718,6 +721,11 @@ export function KnowledgeBase({
718721
<div className='text-muted-foreground text-xs'></div>
719722
</td>
720723

724+
{/* Processing column */}
725+
<td className='px-4 py-3'>
726+
<div className='text-muted-foreground text-xs'></div>
727+
</td>
728+
721729
{/* Status column */}
722730
<td className='px-4 py-3'>
723731
<div className='text-muted-foreground text-xs'></div>

apps/sim/app/w/knowledge/[id]/components/knowledge-base-loading.tsx

Lines changed: 26 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
'use client'
22

3-
import { LibraryBig, Search } from 'lucide-react'
4-
import Link from 'next/link'
3+
import { Search } from 'lucide-react'
54
import { useSidebarStore } from '@/stores/sidebar/store'
5+
import { KnowledgeHeader } from '../../components/knowledge-header/knowledge-header'
66
import { DocumentTableSkeleton } from '../../components/skeletons/table-skeleton'
77

88
interface KnowledgeBaseLoadingProps {
@@ -14,28 +14,29 @@ export function KnowledgeBaseLoading({ knowledgeBaseName }: KnowledgeBaseLoading
1414
const isSidebarCollapsed =
1515
mode === 'expanded' ? !isExpanded : mode === 'collapsed' || mode === 'hover'
1616

17+
const breadcrumbs = [
18+
{
19+
id: 'knowledge-root',
20+
label: 'Knowledge',
21+
href: '/w/knowledge',
22+
},
23+
{
24+
id: 'knowledge-base-loading',
25+
label: knowledgeBaseName,
26+
},
27+
]
28+
1729
return (
1830
<div
1931
className={`flex h-[100vh] flex-col transition-padding duration-200 ${isSidebarCollapsed ? 'pl-14' : 'pl-60'}`}
2032
>
2133
{/* Fixed Header with Breadcrumbs */}
22-
<div className='flex items-center gap-2 px-6 pt-[14px] pb-6'>
23-
<Link
24-
href='/w/knowledge'
25-
prefetch={true}
26-
className='group flex items-center gap-2 font-medium text-sm transition-colors hover:text-muted-foreground'
27-
>
28-
<LibraryBig className='h-[18px] w-[18px] text-muted-foreground transition-colors group-hover:text-muted-foreground/70' />
29-
<span>Knowledge</span>
30-
</Link>
31-
<span className='text-muted-foreground'>/</span>
32-
<span className='font-medium text-sm'>{knowledgeBaseName}</span>
33-
</div>
34+
<KnowledgeHeader breadcrumbs={breadcrumbs} />
3435

3536
<div className='flex flex-1 overflow-hidden'>
3637
<div className='flex flex-1 flex-col overflow-hidden'>
3738
{/* Main Content */}
38-
<div className='flex-1 overflow-auto pt-[4px]'>
39+
<div className='flex-1 overflow-auto'>
3940
<div className='px-6 pb-6'>
4041
{/* Search and Create Section */}
4142
<div className='mb-4 flex items-center justify-between'>
@@ -51,13 +52,16 @@ export function KnowledgeBaseLoading({ knowledgeBaseName }: KnowledgeBaseLoading
5152
</div>
5253
</div>
5354

54-
{/* <button
55-
disabled
56-
className='flex items-center gap-1 rounded-md bg-[#701FFC] px-3 py-[7px] font-[480] text-primary-foreground text-sm shadow-[0_0_0_0_#701FFC] transition-all duration-200 hover:bg-[#6518E6] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)] disabled:opacity-50'
57-
>
58-
<Plus className='h-4 w-4 font-[480]' />
59-
<span>Add Document</span>
60-
</button> */}
55+
<div className='flex items-center gap-3'>
56+
{/* Add Documents Button - disabled state */}
57+
<button
58+
disabled
59+
className='mt-1 mr-1 flex items-center gap-1.5 rounded-md bg-[#701FFC] px-3 py-[7px] font-[480] text-primary-foreground text-sm shadow-[0_0_0_0_#701FFC] transition-all duration-200 hover:bg-[#6518E6] hover:shadow-[0_0_0_3px_rgba(127,47,255,0.12)] disabled:opacity-50'
60+
>
61+
<div className='h-3.5 w-3.5 animate-pulse rounded bg-primary-foreground/30' />
62+
<span>Add Documents</span>
63+
</button>
64+
</div>
6165
</div>
6266

6367
{/* Table container */}

apps/sim/app/w/knowledge/components/knowledge-header/knowledge-header.tsx

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ const HEADER_STYLES = {
2323
link: 'group flex items-center gap-2 font-medium text-sm transition-colors hover:text-muted-foreground',
2424
label: 'font-medium text-sm',
2525
separator: 'text-muted-foreground',
26+
// Always reserve consistent space for actions area
27+
actionsContainer: 'flex h-8 w-8 items-center justify-center',
2628
} as const
2729

2830
interface KnowledgeHeaderOptions {
@@ -60,30 +62,32 @@ export function KnowledgeHeader({ breadcrumbs, options }: KnowledgeHeaderProps)
6062
})}
6163
</div>
6264

63-
{/* Actions Menu - only show if onDeleteKnowledgeBase is provided */}
64-
{options?.onDeleteKnowledgeBase && (
65-
<DropdownMenu>
66-
<DropdownMenuTrigger asChild>
67-
<Button
68-
variant='ghost'
69-
size='sm'
70-
className='h-8 w-8 p-0'
71-
aria-label='Knowledge base actions menu'
72-
>
73-
<MoreHorizontal className='h-4 w-4' />
74-
</Button>
75-
</DropdownMenuTrigger>
76-
<DropdownMenuContent align='end'>
77-
<DropdownMenuItem
78-
onClick={options.onDeleteKnowledgeBase}
79-
className='text-red-600 focus:text-red-600'
80-
>
81-
<Trash2 className='mr-2 h-4 w-4' />
82-
Delete Knowledge Base
83-
</DropdownMenuItem>
84-
</DropdownMenuContent>
85-
</DropdownMenu>
86-
)}
65+
{/* Actions Area - always reserve consistent space */}
66+
<div className={HEADER_STYLES.actionsContainer}>
67+
{options?.onDeleteKnowledgeBase && (
68+
<DropdownMenu>
69+
<DropdownMenuTrigger asChild>
70+
<Button
71+
variant='ghost'
72+
size='sm'
73+
className='h-8 w-8 p-0'
74+
aria-label='Knowledge base actions menu'
75+
>
76+
<MoreHorizontal className='h-4 w-4' />
77+
</Button>
78+
</DropdownMenuTrigger>
79+
<DropdownMenuContent align='end'>
80+
<DropdownMenuItem
81+
onClick={options.onDeleteKnowledgeBase}
82+
className='text-red-600 focus:text-red-600'
83+
>
84+
<Trash2 className='mr-2 h-4 w-4' />
85+
Delete Knowledge Base
86+
</DropdownMenuItem>
87+
</DropdownMenuContent>
88+
</DropdownMenu>
89+
)}
90+
</div>
8791
</div>
8892
)
8993
}

apps/sim/app/w/knowledge/components/skeletons/table-skeleton.tsx

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,12 @@ export function DocumentTableRowSkeleton({ isSidebarCollapsed }: { isSidebarColl
3737
</div>
3838
</td>
3939

40-
{/* Status column */}
40+
{/* Processing Status column */}
41+
<td className='px-4 py-3'>
42+
<div className='h-6 w-16 animate-pulse rounded-md bg-muted' />
43+
</td>
44+
45+
{/* Active Status column */}
4146
<td className='px-4 py-3'>
4247
<div className='h-6 w-16 animate-pulse rounded-md bg-muted' />
4348
</td>
@@ -47,6 +52,7 @@ export function DocumentTableRowSkeleton({ isSidebarCollapsed }: { isSidebarColl
4752
<div className='flex items-center gap-1'>
4853
<div className='h-8 w-8 animate-pulse rounded bg-muted' />
4954
<div className='h-8 w-8 animate-pulse rounded bg-muted' />
55+
<div className='h-8 w-8 animate-pulse rounded bg-muted' />
5056
</div>
5157
</td>
5258
</tr>
@@ -106,17 +112,18 @@ export function DocumentTableSkeleton({
106112
return (
107113
<div className='flex flex-1 flex-col overflow-hidden'>
108114
{/* Table header - fixed */}
109-
<div className='sticky top-0 z-10 border-b bg-background'>
110-
<table className='w-full table-fixed'>
115+
<div className='sticky top-0 z-10 overflow-x-auto border-b bg-background'>
116+
<table className='w-full min-w-[800px] table-fixed'>
111117
<colgroup>
112-
<col className='w-[5%]' />
113-
<col className={`${isSidebarCollapsed ? 'w-[18%]' : 'w-[20%]'}`} />
114-
<col className='w-[10%]' />
115-
<col className='w-[10%]' />
118+
<col className='w-[4%]' />
119+
<col className={`${isSidebarCollapsed ? 'w-[20%]' : 'w-[22%]'}`} />
120+
<col className='w-[8%]' />
121+
<col className='w-[8%]' />
116122
<col className='hidden w-[8%] lg:table-column' />
117-
<col className={`${isSidebarCollapsed ? 'w-[22%]' : 'w-[20%]'}`} />
123+
<col className={`${isSidebarCollapsed ? 'w-[16%]' : 'w-[14%]'}`} />
118124
<col className='w-[10%]' />
119-
<col className='w-[16%]' />
125+
<col className='w-[10%]' />
126+
<col className='w-[12%]' />
120127
</colgroup>
121128
<thead>
122129
<tr>
@@ -138,6 +145,9 @@ export function DocumentTableSkeleton({
138145
<th className='px-4 pt-2 pb-3 text-left font-medium'>
139146
<span className='text-muted-foreground text-xs leading-none'>Uploaded</span>
140147
</th>
148+
<th className='px-4 pt-2 pb-3 text-left font-medium'>
149+
<span className='text-muted-foreground text-xs leading-none'>Processing</span>
150+
</th>
141151
<th className='px-4 pt-2 pb-3 text-left font-medium'>
142152
<span className='text-muted-foreground text-xs leading-none'>Status</span>
143153
</th>
@@ -151,16 +161,17 @@ export function DocumentTableSkeleton({
151161

152162
{/* Table body - scrollable */}
153163
<div className='flex-1 overflow-auto'>
154-
<table className='w-full table-fixed'>
164+
<table className='w-full min-w-[800px] table-fixed'>
155165
<colgroup>
156-
<col className='w-[5%]' />
157-
<col className={`${isSidebarCollapsed ? 'w-[18%]' : 'w-[20%]'}`} />
158-
<col className='w-[10%]' />
159-
<col className='w-[10%]' />
166+
<col className='w-[4%]' />
167+
<col className={`${isSidebarCollapsed ? 'w-[20%]' : 'w-[22%]'}`} />
168+
<col className='w-[8%]' />
169+
<col className='w-[8%]' />
160170
<col className='hidden w-[8%] lg:table-column' />
161-
<col className={`${isSidebarCollapsed ? 'w-[22%]' : 'w-[20%]'}`} />
171+
<col className={`${isSidebarCollapsed ? 'w-[16%]' : 'w-[14%]'}`} />
172+
<col className='w-[10%]' />
162173
<col className='w-[10%]' />
163-
<col className='w-[16%]' />
174+
<col className='w-[12%]' />
164175
</colgroup>
165176
<tbody>
166177
{Array.from({ length: rowCount }).map((_, i) => (

apps/sim/app/w/knowledge/loading.tsx

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,56 @@
11
'use client'
22

3-
import { LibraryBig, Plus, Search } from 'lucide-react'
3+
import { Plus, Search } from 'lucide-react'
44
import { useSidebarStore } from '@/stores/sidebar/store'
5+
import { KnowledgeHeader } from './components/knowledge-header/knowledge-header'
56
import { KnowledgeBaseCardSkeletonGrid } from './components/skeletons/knowledge-base-card-skeleton'
67

78
export default function KnowledgeLoading() {
89
const { mode, isExpanded } = useSidebarStore()
910
const isSidebarCollapsed =
1011
mode === 'expanded' ? !isExpanded : mode === 'collapsed' || mode === 'hover'
1112

13+
const breadcrumbs = [{ id: 'knowledge', label: 'Knowledge' }]
14+
1215
return (
1316
<div
14-
className={`fixed inset-0 flex flex-col transition-all duration-200 ${isSidebarCollapsed ? 'left-14' : 'left-60'}`}
17+
className={`flex h-screen flex-col transition-padding duration-200 ${isSidebarCollapsed ? 'pl-14' : 'pl-60'}`}
1518
>
16-
{/* Fixed Header */}
17-
<div className='flex items-center gap-2 px-6 pt-4 pb-6'>
18-
<LibraryBig className='h-[18px] w-[18px] text-muted-foreground' />
19-
<h1 className='font-medium text-sm'>Knowledge</h1>
20-
</div>
19+
{/* Header */}
20+
<KnowledgeHeader breadcrumbs={breadcrumbs} />
21+
22+
<div className='flex flex-1 overflow-hidden'>
23+
<div className='flex flex-1 flex-col overflow-hidden'>
24+
{/* Main Content */}
25+
<div className='flex-1 overflow-auto'>
26+
<div className='px-6 pb-6'>
27+
{/* Search and Create Section */}
28+
<div className='mb-4 flex items-center justify-between'>
29+
<div className='relative max-w-md flex-1'>
30+
<div className='relative flex items-center'>
31+
<Search className='-translate-y-1/2 pointer-events-none absolute top-1/2 left-3 h-[18px] w-[18px] transform text-muted-foreground' />
32+
<input
33+
type='text'
34+
placeholder='Search knowledge bases...'
35+
disabled
36+
className='h-10 w-full rounded-md border bg-background px-9 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:font-medium file:text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50'
37+
/>
38+
</div>
39+
</div>
2140

22-
{/* Main Content */}
23-
<div className='flex-1 overflow-auto pt-[6px]'>
24-
<div className='px-6 pb-6'>
25-
{/* Search and Create Section */}
26-
<div className='mb-6 flex items-center justify-between'>
27-
<div className='relative max-w-md flex-1'>
28-
<div className='relative flex items-center'>
29-
<Search className='-translate-y-1/2 pointer-events-none absolute top-1/2 left-3 h-[18px] w-[18px] transform text-muted-foreground' />
30-
<input
31-
type='text'
32-
placeholder='Search knowledge bases...'
41+
<button
3342
disabled
34-
className='h-10 w-full rounded-md border bg-background px-9 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:font-medium file:text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50'
35-
/>
43+
className='flex items-center gap-1 rounded-md bg-[#701FFC] px-3 py-[7px] font-[480] text-primary-foreground text-sm shadow-[0_0_0_0_#701FFC] transition-all duration-200 hover:bg-[#6518E6] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)] disabled:opacity-50'
44+
>
45+
<Plus className='h-4 w-4 font-[480]' />
46+
<span>Create</span>
47+
</button>
3648
</div>
37-
</div>
3849

39-
<button
40-
disabled
41-
className='flex items-center gap-1 rounded-md bg-[#701FFC] px-3 py-[7px] font-[480] text-primary-foreground text-sm shadow-[0_0_0_0_#701FFC] transition-all duration-200 hover:bg-[#6518E6] hover:shadow-[0_0_0_4px_rgba(127,47,255,0.15)] disabled:opacity-50'
42-
>
43-
<Plus className='h-4 w-4 font-[480]' />
44-
<span>Create</span>
45-
</button>
50+
{/* Content Area */}
51+
<KnowledgeBaseCardSkeletonGrid count={8} />
52+
</div>
4653
</div>
47-
48-
{/* Content Area */}
49-
<KnowledgeBaseCardSkeletonGrid count={8} />
5054
</div>
5155
</div>
5256
</div>

0 commit comments

Comments
 (0)