fix(settings-ui): fix settings ui, add upload status (#1691)

This commit is contained in:
Waleed
2025-10-18 15:37:12 -07:00
committed by GitHub
parent cc0ace7de6
commit c70c32a3bd
7 changed files with 58 additions and 45 deletions
@@ -238,7 +238,7 @@ export function Copilot() {
<div className='relative flex h-full flex-col'>
{/* Sticky Header with API Keys (only for hosted) */}
{isHosted && (
<div className='sticky top-0 z-10 border-b bg-background px-6 py-4'>
<div className='sticky top-0 z-10 bg-background px-6 py-4'>
<div className='space-y-3'>
{/* API Keys Header */}
<div className='flex items-center justify-between'>
@@ -273,27 +273,25 @@ export function Copilot() {
</div>
) : (
keys.map((k) => (
<div
key={k.id}
className='flex items-center justify-between gap-4 rounded-lg border bg-muted/30 px-3 py-2'
>
<div className='flex min-w-0 items-center gap-3'>
<code className='truncate font-mono text-foreground text-xs'>
{k.displayKey}
</code>
<div key={k.id} className='flex flex-col gap-2'>
<div className='flex items-center justify-between gap-4'>
<div className='flex items-center gap-3'>
<div className='flex h-8 items-center rounded-[8px] bg-muted px-3'>
<code className='font-mono text-foreground text-xs'>{k.displayKey}</code>
</div>
</div>
<Button
variant='ghost'
size='sm'
onClick={() => {
setDeleteKey(k)
setShowDeleteDialog(true)
}}
className='h-8 text-muted-foreground hover:text-foreground'
>
Delete
</Button>
</div>
<Button
variant='ghost'
size='sm'
onClick={() => {
setDeleteKey(k)
setShowDeleteDialog(true)
}}
className='h-7 flex-shrink-0 text-muted-foreground text-xs hover:text-foreground'
>
Delete
</Button>
</div>
))
)}
@@ -308,15 +306,6 @@ export function Copilot() {
{/* Models Header */}
<div>
<h3 className='font-semibold text-foreground text-sm'>Models</h3>
<div className='text-muted-foreground text-xs'>
{isModelsLoading ? (
<Skeleton className='mt-0.5 h-3 w-32' />
) : (
<span>
{enabledCount} of {totalCount} enabled
</span>
)}
</div>
</div>
{/* Models List */}
@@ -473,9 +462,13 @@ export function Copilot() {
function CopilotKeySkeleton() {
return (
<div className='flex items-center justify-between gap-4 rounded-lg border bg-muted/30 px-3 py-2'>
<Skeleton className='h-4 w-48' />
<Skeleton className='h-7 w-14' />
<div className='flex flex-col gap-2'>
<div className='flex items-center justify-between gap-4'>
<div className='flex items-center gap-3'>
<Skeleton className='h-8 w-20 rounded-[8px]' />
</div>
<Skeleton className='h-8 w-14' />
</div>
</div>
)
}
@@ -707,7 +707,10 @@ export function EnvironmentVariables({
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter className='flex'>
<AlertDialogCancel onClick={handleCancel} className='h-9 w-full rounded-[8px]'>
<AlertDialogCancel
onClick={handleCancel}
className='h-9 w-full rounded-[8px] bg-red-500 text-white transition-all duration-200 hover:bg-red-600 dark:bg-red-500 dark:hover:bg-red-600'
>
Discard Changes
</AlertDialogCancel>
{hasConflicts ? (
@@ -715,7 +718,7 @@ export function EnvironmentVariables({
<TooltipTrigger asChild>
<AlertDialogAction
disabled={true}
className='h-9 w-full cursor-not-allowed rounded-[8px] opacity-50 transition-all duration-200'
className='h-9 w-full cursor-not-allowed rounded-[8px] bg-primary text-white opacity-50 transition-all duration-200'
>
Save Changes
</AlertDialogAction>
@@ -725,7 +728,7 @@ export function EnvironmentVariables({
) : (
<AlertDialogAction
onClick={handleSave}
className='h-9 w-full rounded-[8px] transition-all duration-200'
className='h-9 w-full rounded-[8px] bg-primary text-white transition-all duration-200 hover:bg-primary/90'
>
Save Changes
</AlertDialogAction>
@@ -1,7 +1,7 @@
'use client'
import { useEffect, useMemo, useRef, useState } from 'react'
import { Download, Search, Trash2, Upload } from 'lucide-react'
import { Download, Search, Trash2 } from 'lucide-react'
import { useParams } from 'next/navigation'
import { Input } from '@/components/ui'
import { Button } from '@/components/ui/button'
@@ -46,6 +46,7 @@ export function FileUploads() {
const [uploading, setUploading] = useState(false)
const [deletingFileId, setDeletingFileId] = useState<string | null>(null)
const [uploadError, setUploadError] = useState<string | null>(null)
const [uploadProgress, setUploadProgress] = useState({ completed: 0, total: 0 })
const fileInputRef = useRef<HTMLInputElement>(null)
const { permissions: workspacePermissions, loading: permissionsLoading } =
@@ -94,9 +95,12 @@ export function FileUploads() {
if (!ok) unsupported.push(f.name)
return ok
})
setUploadProgress({ completed: 0, total: allowedFiles.length })
let lastError: string | null = null
for (const selectedFile of allowedFiles) {
for (let i = 0; i < allowedFiles.length; i++) {
const selectedFile = allowedFiles[i]
try {
const formData = new FormData()
formData.append('file', selectedFile)
@@ -109,6 +113,8 @@ export function FileUploads() {
const data = await response.json()
if (!data.success) {
lastError = data.error || 'Upload failed'
} else {
setUploadProgress({ completed: i + 1, total: allowedFiles.length })
}
} catch (err) {
logger.error('Error uploading file:', err)
@@ -127,6 +133,7 @@ export function FileUploads() {
setTimeout(() => setUploadError(null), 5000)
} finally {
setUploading(false)
setUploadProgress({ completed: 0, total: 0 })
if (fileInputRef.current) {
fileInputRef.current.value = ''
}
@@ -225,6 +232,7 @@ export function FileUploads() {
onChange={handleFileChange}
disabled={uploading}
accept={ACCEPT_ATTR}
multiple
/>
<Button
onClick={handleUploadClick}
@@ -232,8 +240,11 @@ export function FileUploads() {
variant='ghost'
className='h-9 rounded-[8px] border bg-background px-3 shadow-xs hover:bg-muted focus:outline-none focus-visible:ring-0 focus-visible:ring-offset-0'
>
<Upload className='mr-2 h-4 w-4 stroke-[2px]' />
{uploading ? 'Uploading...' : 'Upload File'}
{uploading && uploadProgress.total > 0
? `Uploading ${uploadProgress.completed}/${uploadProgress.total}...`
: uploading
? 'Uploading...'
: 'Upload File'}
</Button>
</div>
)}
@@ -203,7 +203,7 @@ export function SettingsNavigation({
return (
<div className='flex h-full flex-col'>
<div className='flex-1 px-2 py-4'>
<div className='flex-1 overflow-y-auto px-2 py-4'>
{navigationItems.map((item) => (
<div key={item.id} className='mb-1'>
<button
@@ -235,7 +235,12 @@ export function CancelSubscription({ subscription, subscriptionData }: CancelSub
? 'Your subscription is set to cancel at the end of the billing period. You can reactivate it or manage other settings.'
: `You'll be redirected to Stripe to manage your subscription. You'll keep access until ${formatDate(
periodEndDate
)}, then downgrade to free plan.`}
)}, then downgrade to free plan.`}{' '}
{!isCancelAtPeriodEnd && (
<span className='text-red-500 dark:text-red-500'>
This action cannot be undone.
</span>
)}
</AlertDialogDescription>
</AlertDialogHeader>
@@ -37,7 +37,8 @@ export function RemoveMemberDialog({
<DialogDescription>
{isSelfRemoval
? 'Are you sure you want to leave this organization? You will lose access to all team resources.'
: `Are you sure you want to remove ${memberName} from the team?`}
: `Are you sure you want to remove ${memberName} from the team?`}{' '}
<span className='text-red-500 dark:text-red-500'>This action cannot be undone.</span>
</DialogDescription>
</DialogHeader>
@@ -68,7 +69,7 @@ export function RemoveMemberDialog({
<Button
variant='destructive'
onClick={() => onConfirmRemove(shouldReduceSeats)}
className='h-9 rounded-[8px]'
className='h-9 rounded-[8px] bg-red-500 text-white transition-all duration-200 hover:bg-red-600 dark:bg-red-500 dark:hover:bg-red-600'
>
{isSelfRemoval ? 'Leave Organization' : 'Remove'}
</Button>
@@ -279,7 +279,7 @@ export function TeamMembers({
}
onRemoveMember(currentUserMember)
}}
className='w-full text-red-600 hover:bg-red-50 hover:text-red-700 dark:hover:bg-red-950/20'
className='w-full hover:bg-muted'
>
<LogOut className='mr-2 h-4 w-4' />
Leave Organization