mirror of
https://github.com/simstudioai/sim.git
synced 2026-01-22 13:28:04 -05:00
updates
This commit is contained in:
@@ -135,7 +135,7 @@ export async function GET(
|
||||
|
||||
/**
|
||||
* DELETE /api/table/[tableId]?workspaceId=xxx
|
||||
* Delete a table (soft delete)
|
||||
* Delete a table (hard delete)
|
||||
*/
|
||||
export async function DELETE(
|
||||
request: NextRequest,
|
||||
@@ -165,18 +165,16 @@ export async function DELETE(
|
||||
return NextResponse.json({ error: 'Access denied' }, { status: 403 })
|
||||
}
|
||||
|
||||
// Soft delete table
|
||||
// Delete all rows first
|
||||
await db.delete(userTableRows).where(eq(userTableRows.tableId, tableId))
|
||||
|
||||
// Hard delete table
|
||||
const [deletedTable] = await db
|
||||
.update(userTableDefinitions)
|
||||
.set({
|
||||
deletedAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
})
|
||||
.delete(userTableDefinitions)
|
||||
.where(
|
||||
and(
|
||||
eq(userTableDefinitions.id, tableId),
|
||||
eq(userTableDefinitions.workspaceId, validated.workspaceId),
|
||||
isNull(userTableDefinitions.deletedAt)
|
||||
eq(userTableDefinitions.workspaceId, validated.workspaceId)
|
||||
)
|
||||
)
|
||||
.returning()
|
||||
@@ -185,9 +183,6 @@ export async function DELETE(
|
||||
return NextResponse.json({ error: 'Table not found' }, { status: 404 })
|
||||
}
|
||||
|
||||
// Delete all rows
|
||||
await db.delete(userTableRows).where(eq(userTableRows.tableId, tableId))
|
||||
|
||||
logger.info(`[${requestId}] Deleted table ${tableId}`)
|
||||
|
||||
return NextResponse.json({
|
||||
|
||||
@@ -61,8 +61,7 @@ export function AddRowModal({ isOpen, onClose, table, onSuccess }: AddRowModalPr
|
||||
const cleanData: Record<string, any> = {}
|
||||
columns.forEach((col) => {
|
||||
const value = rowData[col.name]
|
||||
const isRequired = !col.optional
|
||||
if (isRequired || (value !== '' && value !== null && value !== undefined)) {
|
||||
if (col.required || (value !== '' && value !== null && value !== undefined)) {
|
||||
if (col.type === 'number') {
|
||||
cleanData[col.name] = value === '' ? null : Number(value)
|
||||
} else if (col.type === 'json') {
|
||||
@@ -132,7 +131,7 @@ export function AddRowModal({ isOpen, onClose, table, onSuccess }: AddRowModalPr
|
||||
<div key={column.name} className='flex flex-col gap-[8px]'>
|
||||
<Label htmlFor={column.name} className='font-medium text-[13px]'>
|
||||
{column.name}
|
||||
{!column.optional && <span className='text-[var(--text-error)]'> *</span>}
|
||||
{column.required && <span className='text-[var(--text-error)]'> *</span>}
|
||||
{column.unique && (
|
||||
<span className='ml-[6px] font-normal text-[11px] text-[var(--text-tertiary)]'>
|
||||
(unique)
|
||||
@@ -166,7 +165,7 @@ export function AddRowModal({ isOpen, onClose, table, onSuccess }: AddRowModalPr
|
||||
placeholder='{"key": "value"}'
|
||||
rows={4}
|
||||
className='font-mono text-[12px]'
|
||||
required={!column.optional}
|
||||
required={column.required}
|
||||
/>
|
||||
) : (
|
||||
<Input
|
||||
@@ -180,13 +179,13 @@ export function AddRowModal({ isOpen, onClose, table, onSuccess }: AddRowModalPr
|
||||
}
|
||||
placeholder={`Enter ${column.name}`}
|
||||
className='h-[38px]'
|
||||
required={!column.optional}
|
||||
required={column.required}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className='text-[12px] text-[var(--text-tertiary)]'>
|
||||
Type: {column.type}
|
||||
{column.optional && ' (optional)'}
|
||||
{!column.required && ' (optional)'}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -142,7 +142,7 @@ export function EditRowModal({ isOpen, onClose, table, row, onSuccess }: EditRow
|
||||
<div key={column.name} className='flex flex-col gap-[8px]'>
|
||||
<Label htmlFor={column.name} className='font-medium text-[13px]'>
|
||||
{column.name}
|
||||
{!column.optional && <span className='text-[var(--text-error)]'> *</span>}
|
||||
{column.required && <span className='text-[var(--text-error)]'> *</span>}
|
||||
{column.unique && (
|
||||
<span className='ml-[6px] font-normal text-[11px] text-[var(--text-tertiary)]'>
|
||||
(unique)
|
||||
@@ -176,7 +176,7 @@ export function EditRowModal({ isOpen, onClose, table, row, onSuccess }: EditRow
|
||||
placeholder='{"key": "value"}'
|
||||
rows={4}
|
||||
className='font-mono text-[12px]'
|
||||
required={!column.optional}
|
||||
required={column.required}
|
||||
/>
|
||||
) : (
|
||||
<Input
|
||||
@@ -190,13 +190,13 @@ export function EditRowModal({ isOpen, onClose, table, row, onSuccess }: EditRow
|
||||
}
|
||||
placeholder={`Enter ${column.name}`}
|
||||
className='h-[38px]'
|
||||
required={!column.optional}
|
||||
required={column.required}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className='text-[12px] text-[var(--text-tertiary)]'>
|
||||
Type: {column.type}
|
||||
{column.optional && ' (optional)'}
|
||||
{!column.required && ' (optional)'}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -435,7 +435,7 @@ export function TableDataViewer() {
|
||||
<Badge variant='outline' size='sm'>
|
||||
{column.type}
|
||||
</Badge>
|
||||
{!column.optional && (
|
||||
{column.required && (
|
||||
<span className='text-[10px] text-[var(--text-error)]'>*</span>
|
||||
)}
|
||||
</div>
|
||||
@@ -675,9 +675,9 @@ export function TableDataViewer() {
|
||||
</TableCell>
|
||||
<TableCell className='text-[12px]'>
|
||||
<div className='flex gap-[6px]'>
|
||||
{column.optional && (
|
||||
<Badge variant='gray' size='sm'>
|
||||
optional
|
||||
{column.required && (
|
||||
<Badge variant='red' size='sm'>
|
||||
required
|
||||
</Badge>
|
||||
)}
|
||||
{column.unique && (
|
||||
@@ -685,7 +685,7 @@ export function TableDataViewer() {
|
||||
unique
|
||||
</Badge>
|
||||
)}
|
||||
{!column.optional && !column.unique && (
|
||||
{!column.required && !column.unique && (
|
||||
<span className='text-[var(--text-muted)]'>—</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -24,7 +24,7 @@ const logger = createLogger('CreateTableModal')
|
||||
interface ColumnDefinition {
|
||||
name: string
|
||||
type: 'string' | 'number' | 'boolean' | 'date' | 'json'
|
||||
optional: boolean
|
||||
required: boolean
|
||||
unique: boolean
|
||||
}
|
||||
|
||||
@@ -48,14 +48,14 @@ export function CreateTableModal({ isOpen, onClose }: CreateTableModalProps) {
|
||||
const [tableName, setTableName] = useState('')
|
||||
const [description, setDescription] = useState('')
|
||||
const [columns, setColumns] = useState<ColumnDefinition[]>([
|
||||
{ name: '', type: 'string', optional: false, unique: false },
|
||||
{ name: '', type: 'string', required: true, unique: false },
|
||||
])
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
|
||||
const createTable = useCreateTable(workspaceId)
|
||||
|
||||
const handleAddColumn = () => {
|
||||
setColumns([...columns, { name: '', type: 'string', optional: false, unique: false }])
|
||||
setColumns([...columns, { name: '', type: 'string', required: true, unique: false }])
|
||||
}
|
||||
|
||||
const handleRemoveColumn = (index: number) => {
|
||||
@@ -110,7 +110,7 @@ export function CreateTableModal({ isOpen, onClose }: CreateTableModalProps) {
|
||||
// Reset form
|
||||
setTableName('')
|
||||
setDescription('')
|
||||
setColumns([{ name: '', type: 'string', optional: false, unique: false }])
|
||||
setColumns([{ name: '', type: 'string', required: true, unique: false }])
|
||||
setError(null)
|
||||
onClose()
|
||||
} catch (err) {
|
||||
@@ -123,7 +123,7 @@ export function CreateTableModal({ isOpen, onClose }: CreateTableModalProps) {
|
||||
// Reset form on close
|
||||
setTableName('')
|
||||
setDescription('')
|
||||
setColumns([{ name: '', type: 'string', optional: false, unique: false }])
|
||||
setColumns([{ name: '', type: 'string', required: true, unique: false }])
|
||||
setError(null)
|
||||
onClose()
|
||||
}
|
||||
@@ -202,7 +202,7 @@ export function CreateTableModal({ isOpen, onClose }: CreateTableModalProps) {
|
||||
<div className='flex items-center gap-[10px] rounded-[6px] bg-[var(--bg-secondary)] px-[12px] py-[8px] text-[11px] font-semibold text-[var(--text-tertiary)]'>
|
||||
<div className='flex-1'>Column Name</div>
|
||||
<div className='w-[110px]'>Type</div>
|
||||
<div className='w-[70px] text-center'>Optional</div>
|
||||
<div className='w-[70px] text-center'>Required</div>
|
||||
<div className='w-[70px] text-center'>Unique</div>
|
||||
<div className='w-[36px]' />
|
||||
</div>
|
||||
@@ -239,12 +239,12 @@ export function CreateTableModal({ isOpen, onClose }: CreateTableModalProps) {
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Optional Checkbox */}
|
||||
{/* Required Checkbox */}
|
||||
<div className='flex w-[70px] items-center justify-center'>
|
||||
<Checkbox
|
||||
checked={column.optional}
|
||||
checked={column.required}
|
||||
onCheckedChange={(checked) =>
|
||||
handleColumnChange(index, 'optional', checked === true)
|
||||
handleColumnChange(index, 'required', checked === true)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
@@ -277,9 +277,8 @@ export function CreateTableModal({ isOpen, onClose }: CreateTableModalProps) {
|
||||
</div>
|
||||
|
||||
<p className='text-[12px] text-[var(--text-tertiary)]'>
|
||||
Columns are <span className='font-medium'>required</span> by default. Check{' '}
|
||||
<span className='font-medium'>optional</span> for nullable fields, or{' '}
|
||||
<span className='font-medium'>unique</span> to prevent duplicates.
|
||||
Mark columns as <span className='font-medium'>unique</span> to prevent duplicate
|
||||
values (e.g., id, email)
|
||||
</p>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -256,9 +256,9 @@ export function TableCard({ table, workspaceId }: TableCardProps) {
|
||||
</TableCell>
|
||||
<TableCell className='text-[12px]'>
|
||||
<div className='flex gap-[6px]'>
|
||||
{column.optional && (
|
||||
<Badge variant='gray' size='sm'>
|
||||
optional
|
||||
{column.required && (
|
||||
<Badge variant='red' size='sm'>
|
||||
required
|
||||
</Badge>
|
||||
)}
|
||||
{column.unique && (
|
||||
@@ -266,7 +266,7 @@ export function TableCard({ table, workspaceId }: TableCardProps) {
|
||||
unique
|
||||
</Badge>
|
||||
)}
|
||||
{!column.optional && !column.unique && (
|
||||
{!column.required && !column.unique && (
|
||||
<span className='text-[var(--text-muted)]'>—</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { COLUMN_TYPES, NAME_PATTERN, TABLE_LIMITS } from './constants'
|
||||
export interface ColumnDefinition {
|
||||
name: string
|
||||
type: ColumnType
|
||||
optional?: boolean
|
||||
required?: boolean
|
||||
unique?: boolean
|
||||
}
|
||||
|
||||
@@ -150,8 +150,8 @@ export function validateRowAgainstSchema(
|
||||
for (const column of schema.columns) {
|
||||
const value = data[column.name]
|
||||
|
||||
// Check required fields (columns are required by default unless marked optional)
|
||||
if (!column.optional && (value === undefined || value === null)) {
|
||||
// Check required fields
|
||||
if (column.required && (value === undefined || value === null)) {
|
||||
errors.push(`Missing required field: ${column.name}`)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ export type ColumnType = 'string' | 'number' | 'boolean' | 'date' | 'json'
|
||||
export interface ColumnDefinition {
|
||||
name: string
|
||||
type: ColumnType
|
||||
optional?: boolean
|
||||
required?: boolean
|
||||
unique?: boolean
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user