mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-06 03:00:16 -04:00
renames & refactors
This commit is contained in:
@@ -1,13 +1,16 @@
|
||||
import { db } from '@sim/db'
|
||||
import { userTableDefinitions, userTableRows } from '@sim/db/schema'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { and, eq, isNull } from 'drizzle-orm'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { checkHybridAuth } from '@/lib/auth/hybrid'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import type { TableColumnData, TableSchemaData } from '../utils'
|
||||
import { checkTableAccess, checkTableWriteAccess, verifyTableWorkspace } from '../utils'
|
||||
import { deleteTable, getTableById } from '@/lib/table'
|
||||
import type { TableSchemaData } from '../utils'
|
||||
import {
|
||||
checkTableAccess,
|
||||
checkTableWriteAccess,
|
||||
normalizeColumn,
|
||||
verifyTableWorkspace,
|
||||
} from '../utils'
|
||||
|
||||
const logger = createLogger('TableDetailAPI')
|
||||
|
||||
@@ -28,21 +31,6 @@ interface TableRouteParams {
|
||||
params: Promise<{ tableId: string }>
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a column definition ensuring all optional fields have explicit values.
|
||||
*
|
||||
* @param col - The column data to normalize
|
||||
* @returns Normalized column with explicit required and unique values
|
||||
*/
|
||||
function normalizeColumn(col: TableColumnData): TableColumnData {
|
||||
return {
|
||||
name: col.name,
|
||||
type: col.type,
|
||||
required: col.required ?? false,
|
||||
unique: col.unique ?? false,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/table/[tableId]?workspaceId=xxx
|
||||
*
|
||||
@@ -109,12 +97,8 @@ export async function GET(request: NextRequest, { params }: TableRouteParams) {
|
||||
}
|
||||
}
|
||||
|
||||
// Get table (workspaceId validation is now handled by access check)
|
||||
const [table] = await db
|
||||
.select()
|
||||
.from(userTableDefinitions)
|
||||
.where(and(eq(userTableDefinitions.id, tableId), isNull(userTableDefinitions.deletedAt)))
|
||||
.limit(1)
|
||||
// Get table using service layer
|
||||
const table = await getTableById(tableId)
|
||||
|
||||
if (!table) {
|
||||
return NextResponse.json({ error: 'Table not found' }, { status: 404 })
|
||||
@@ -136,8 +120,14 @@ export async function GET(request: NextRequest, { params }: TableRouteParams) {
|
||||
},
|
||||
rowCount: table.rowCount,
|
||||
maxRows: table.maxRows,
|
||||
createdAt: table.createdAt.toISOString(),
|
||||
updatedAt: table.updatedAt.toISOString(),
|
||||
createdAt:
|
||||
table.createdAt instanceof Date
|
||||
? table.createdAt.toISOString()
|
||||
: String(table.createdAt),
|
||||
updatedAt:
|
||||
table.updatedAt instanceof Date
|
||||
? table.updatedAt.toISOString()
|
||||
: String(table.updatedAt),
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -157,14 +147,15 @@ export async function GET(request: NextRequest, { params }: TableRouteParams) {
|
||||
/**
|
||||
* DELETE /api/table/[tableId]?workspaceId=xxx
|
||||
*
|
||||
* Permanently deletes a table and all its rows.
|
||||
* Soft deletes a table.
|
||||
*
|
||||
* @param request - The incoming HTTP request
|
||||
* @param context - Route context containing tableId param
|
||||
* @returns JSON response confirming deletion or error
|
||||
*
|
||||
* @remarks
|
||||
* This performs a hard delete, removing all data permanently.
|
||||
* This performs a soft delete, marking the table as deleted.
|
||||
* Rows remain in the database but become inaccessible.
|
||||
* The operation requires write access to the table.
|
||||
*/
|
||||
export async function DELETE(request: NextRequest, { params }: TableRouteParams) {
|
||||
@@ -192,20 +183,8 @@ export async function DELETE(request: NextRequest, { params }: TableRouteParams)
|
||||
return NextResponse.json({ error: 'Access denied' }, { status: 403 })
|
||||
}
|
||||
|
||||
// Delete all rows first
|
||||
await db.delete(userTableRows).where(eq(userTableRows.tableId, tableId))
|
||||
|
||||
// Hard delete table
|
||||
const [deletedTable] = await db
|
||||
.delete(userTableDefinitions)
|
||||
.where(eq(userTableDefinitions.id, tableId))
|
||||
.returning()
|
||||
|
||||
if (!deletedTable) {
|
||||
return NextResponse.json({ error: 'Table not found' }, { status: 404 })
|
||||
}
|
||||
|
||||
logger.info(`[${requestId}] Deleted table ${tableId} for user ${authResult.userId}`)
|
||||
// Soft delete table using service layer
|
||||
await deleteTable(tableId, requestId)
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import { db } from '@sim/db'
|
||||
import { permissions, userTableDefinitions, workspace } from '@sim/db/schema'
|
||||
import { permissions, workspace } from '@sim/db/schema'
|
||||
import { createLogger } from '@sim/logger'
|
||||
import { and, eq, isNull, sql } from 'drizzle-orm'
|
||||
import { and, eq } from 'drizzle-orm'
|
||||
import { type NextRequest, NextResponse } from 'next/server'
|
||||
import { z } from 'zod'
|
||||
import { checkHybridAuth } from '@/lib/auth/hybrid'
|
||||
import { generateRequestId } from '@/lib/core/utils/request'
|
||||
import { TABLE_LIMITS, validateTableName, validateTableSchema } from '@/lib/table'
|
||||
import type { TableSchema } from '@/lib/table/validation/schema'
|
||||
import type { TableColumnData, TableSchemaData } from './utils'
|
||||
import { createTable, listTables, TABLE_LIMITS } from '@/lib/table'
|
||||
import { normalizeColumn, type TableSchemaData } from './utils'
|
||||
|
||||
const logger = createLogger('TableAPI')
|
||||
|
||||
@@ -147,31 +146,6 @@ async function checkWorkspaceAccess(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Column input type that accepts both Zod-inferred columns and database columns.
|
||||
*/
|
||||
interface ColumnInput {
|
||||
name: string
|
||||
type: 'string' | 'number' | 'boolean' | 'date' | 'json'
|
||||
required?: boolean
|
||||
unique?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a column definition by ensuring all optional fields have explicit values.
|
||||
*
|
||||
* @param col - The column definition to normalize
|
||||
* @returns A normalized column with explicit required and unique values
|
||||
*/
|
||||
function normalizeColumn(col: ColumnInput): TableColumnData {
|
||||
return {
|
||||
name: col.name,
|
||||
type: col.type,
|
||||
required: col.required ?? false,
|
||||
unique: col.unique ?? false,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/table
|
||||
*
|
||||
@@ -207,24 +181,6 @@ export async function POST(request: NextRequest) {
|
||||
const body: unknown = await request.json()
|
||||
const params = CreateTableSchema.parse(body)
|
||||
|
||||
// Validate table name
|
||||
const nameValidation = validateTableName(params.name)
|
||||
if (!nameValidation.valid) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Invalid table name', details: nameValidation.errors },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
// Validate schema
|
||||
const schemaValidation = validateTableSchema(params.schema as TableSchema)
|
||||
if (!schemaValidation.valid) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Invalid table schema', details: schemaValidation.errors },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
// Check workspace access
|
||||
const { hasAccess, canWrite } = await checkWorkspaceAccess(
|
||||
params.workspaceId,
|
||||
@@ -235,72 +191,22 @@ export async function POST(request: NextRequest) {
|
||||
return NextResponse.json({ error: 'Access denied' }, { status: 403 })
|
||||
}
|
||||
|
||||
// Check workspace table limit
|
||||
const [tableCount] = await db
|
||||
.select({ count: sql<number>`count(*)` })
|
||||
.from(userTableDefinitions)
|
||||
.where(
|
||||
and(
|
||||
eq(userTableDefinitions.workspaceId, params.workspaceId),
|
||||
isNull(userTableDefinitions.deletedAt)
|
||||
)
|
||||
)
|
||||
|
||||
if (Number(tableCount.count) >= TABLE_LIMITS.MAX_TABLES_PER_WORKSPACE) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: `Workspace table limit reached (${TABLE_LIMITS.MAX_TABLES_PER_WORKSPACE} tables max)`,
|
||||
},
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
// Check for duplicate table name
|
||||
const [existing] = await db
|
||||
.select({ id: userTableDefinitions.id })
|
||||
.from(userTableDefinitions)
|
||||
.where(
|
||||
and(
|
||||
eq(userTableDefinitions.workspaceId, params.workspaceId),
|
||||
eq(userTableDefinitions.name, params.name),
|
||||
isNull(userTableDefinitions.deletedAt)
|
||||
)
|
||||
)
|
||||
.limit(1)
|
||||
|
||||
if (existing) {
|
||||
return NextResponse.json(
|
||||
{ error: `Table "${params.name}" already exists in this workspace` },
|
||||
{ status: 400 }
|
||||
)
|
||||
}
|
||||
|
||||
// Normalize schema to ensure all fields have explicit defaults
|
||||
const normalizedSchema: TableSchemaData = {
|
||||
columns: params.schema.columns.map(normalizeColumn),
|
||||
}
|
||||
|
||||
// Create table
|
||||
const tableId = `tbl_${crypto.randomUUID().replace(/-/g, '')}`
|
||||
const now = new Date()
|
||||
|
||||
const [table] = await db
|
||||
.insert(userTableDefinitions)
|
||||
.values({
|
||||
id: tableId,
|
||||
workspaceId: params.workspaceId,
|
||||
// Create table using service layer
|
||||
const table = await createTable(
|
||||
{
|
||||
name: params.name,
|
||||
description: params.description,
|
||||
schema: normalizedSchema,
|
||||
maxRows: TABLE_LIMITS.MAX_ROWS_PER_TABLE,
|
||||
rowCount: 0,
|
||||
createdBy: authResult.userId,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
})
|
||||
.returning()
|
||||
|
||||
logger.info(`[${requestId}] Created table ${tableId} in workspace ${params.workspaceId}`)
|
||||
workspaceId: params.workspaceId,
|
||||
userId: authResult.userId,
|
||||
},
|
||||
requestId
|
||||
)
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
@@ -312,8 +218,14 @@ export async function POST(request: NextRequest) {
|
||||
schema: table.schema,
|
||||
rowCount: table.rowCount,
|
||||
maxRows: table.maxRows,
|
||||
createdAt: table.createdAt.toISOString(),
|
||||
updatedAt: table.updatedAt.toISOString(),
|
||||
createdAt:
|
||||
table.createdAt instanceof Date
|
||||
? table.createdAt.toISOString()
|
||||
: String(table.createdAt),
|
||||
updatedAt:
|
||||
table.updatedAt instanceof Date
|
||||
? table.updatedAt.toISOString()
|
||||
: String(table.updatedAt),
|
||||
},
|
||||
message: 'Table created successfully',
|
||||
},
|
||||
@@ -326,6 +238,18 @@ export async function POST(request: NextRequest) {
|
||||
)
|
||||
}
|
||||
|
||||
// Handle service layer errors with specific messages
|
||||
if (error instanceof Error) {
|
||||
if (
|
||||
error.message.includes('Invalid table name') ||
|
||||
error.message.includes('Invalid schema') ||
|
||||
error.message.includes('already exists') ||
|
||||
error.message.includes('maximum table limit')
|
||||
) {
|
||||
return NextResponse.json({ error: error.message }, { status: 400 })
|
||||
}
|
||||
}
|
||||
|
||||
logger.error(`[${requestId}] Error creating table:`, error)
|
||||
return NextResponse.json({ error: 'Failed to create table' }, { status: 500 })
|
||||
}
|
||||
@@ -368,26 +292,8 @@ export async function GET(request: NextRequest) {
|
||||
return NextResponse.json({ error: 'Access denied' }, { status: 403 })
|
||||
}
|
||||
|
||||
// Get tables
|
||||
const tables = await db
|
||||
.select({
|
||||
id: userTableDefinitions.id,
|
||||
name: userTableDefinitions.name,
|
||||
description: userTableDefinitions.description,
|
||||
schema: userTableDefinitions.schema,
|
||||
rowCount: userTableDefinitions.rowCount,
|
||||
maxRows: userTableDefinitions.maxRows,
|
||||
createdAt: userTableDefinitions.createdAt,
|
||||
updatedAt: userTableDefinitions.updatedAt,
|
||||
})
|
||||
.from(userTableDefinitions)
|
||||
.where(
|
||||
and(
|
||||
eq(userTableDefinitions.workspaceId, params.workspaceId),
|
||||
isNull(userTableDefinitions.deletedAt)
|
||||
)
|
||||
)
|
||||
.orderBy(userTableDefinitions.createdAt)
|
||||
// Get tables using service layer
|
||||
const tables = await listTables(params.workspaceId)
|
||||
|
||||
logger.info(`[${requestId}] Listed ${tables.length} tables in workspace ${params.workspaceId}`)
|
||||
|
||||
@@ -401,8 +307,10 @@ export async function GET(request: NextRequest) {
|
||||
schema: {
|
||||
columns: schemaData.columns.map(normalizeColumn),
|
||||
},
|
||||
createdAt: t.createdAt.toISOString(),
|
||||
updatedAt: t.updatedAt.toISOString(),
|
||||
createdAt:
|
||||
t.createdAt instanceof Date ? t.createdAt.toISOString() : String(t.createdAt),
|
||||
updatedAt:
|
||||
t.updatedAt instanceof Date ? t.updatedAt.toISOString() : String(t.updatedAt),
|
||||
}
|
||||
}),
|
||||
totalCount: tables.length,
|
||||
|
||||
@@ -485,3 +485,18 @@ export function serverErrorResponse(
|
||||
): NextResponse<ApiErrorResponse> {
|
||||
return errorResponse(message, 500)
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes a column definition by ensuring all optional fields have explicit values.
|
||||
*
|
||||
* @param col - The column definition to normalize
|
||||
* @returns A normalized column with explicit required and unique values
|
||||
*/
|
||||
export function normalizeColumn(col: TableColumnData): TableColumnData {
|
||||
return {
|
||||
name: col.name,
|
||||
type: col.type,
|
||||
required: col.required ?? false,
|
||||
unique: col.unique ?? false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* @module tables/[tableId]/components
|
||||
*/
|
||||
export * from './filter-builder'
|
||||
export * from './row-modal'
|
||||
|
||||
export * from './table-action-bar'
|
||||
export * from './table-query-builder'
|
||||
export * from './table-row-modal'
|
||||
|
||||
@@ -42,9 +42,9 @@ interface Column {
|
||||
}
|
||||
|
||||
/**
|
||||
* Props for the FilterBuilder component.
|
||||
* Props for the TableQueryBuilder component.
|
||||
*/
|
||||
interface FilterBuilderProps {
|
||||
interface TableQueryBuilderProps {
|
||||
/** Available columns for filtering */
|
||||
columns: Column[]
|
||||
/** Callback when query options should be applied */
|
||||
@@ -169,14 +169,14 @@ function conditionsToFilter(conditions: FilterCondition[]): Record<string, Filte
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* <FilterBuilder
|
||||
* <TableQueryBuilder
|
||||
* columns={tableColumns}
|
||||
* onApply={(options) => setQueryOptions(options)}
|
||||
* onAddRow={() => setShowAddModal(true)}
|
||||
* />
|
||||
* ```
|
||||
*/
|
||||
export function FilterBuilder({ columns, onApply, onAddRow }: FilterBuilderProps) {
|
||||
export function TableQueryBuilder({ columns, onApply, onAddRow }: TableQueryBuilderProps) {
|
||||
const [conditions, setConditions] = useState<FilterCondition[]>([])
|
||||
const [sortConfig, setSortConfig] = useState<SortConfig | null>(null)
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
import { Input } from '@/components/ui/input'
|
||||
import type { ColumnDefinition, TableSchema } from '@/lib/table'
|
||||
|
||||
const logger = createLogger('RowModal')
|
||||
const logger = createLogger('TableRowModal')
|
||||
|
||||
/**
|
||||
* Represents row data from the table.
|
||||
@@ -49,14 +49,14 @@ export interface TableInfo {
|
||||
/**
|
||||
* Modal mode determines the operation and UI.
|
||||
*/
|
||||
export type RowModalMode = 'add' | 'edit' | 'delete'
|
||||
export type TableRowModalMode = 'add' | 'edit' | 'delete'
|
||||
|
||||
/**
|
||||
* Props for the RowModal component.
|
||||
* Props for the TableRowModal component.
|
||||
*/
|
||||
export interface RowModalProps {
|
||||
export interface TableRowModalProps {
|
||||
/** The operation mode */
|
||||
mode: RowModalMode
|
||||
mode: TableRowModalMode
|
||||
/** Whether the modal is open */
|
||||
isOpen: boolean
|
||||
/** Callback when the modal should close */
|
||||
@@ -147,7 +147,7 @@ function formatValueForInput(value: unknown, type: string): string {
|
||||
*
|
||||
* @example Add mode:
|
||||
* ```tsx
|
||||
* <RowModal
|
||||
* <TableRowModal
|
||||
* mode="add"
|
||||
* isOpen={isOpen}
|
||||
* onClose={() => setIsOpen(false)}
|
||||
@@ -158,7 +158,7 @@ function formatValueForInput(value: unknown, type: string): string {
|
||||
*
|
||||
* @example Edit mode:
|
||||
* ```tsx
|
||||
* <RowModal
|
||||
* <TableRowModal
|
||||
* mode="edit"
|
||||
* isOpen={isOpen}
|
||||
* onClose={() => setIsOpen(false)}
|
||||
@@ -170,7 +170,7 @@ function formatValueForInput(value: unknown, type: string): string {
|
||||
*
|
||||
* @example Delete mode:
|
||||
* ```tsx
|
||||
* <RowModal
|
||||
* <TableRowModal
|
||||
* mode="delete"
|
||||
* isOpen={isOpen}
|
||||
* onClose={() => setIsOpen(false)}
|
||||
@@ -180,7 +180,15 @@ function formatValueForInput(value: unknown, type: string): string {
|
||||
* />
|
||||
* ```
|
||||
*/
|
||||
export function RowModal({ mode, isOpen, onClose, table, row, rowIds, onSuccess }: RowModalProps) {
|
||||
export function TableRowModal({
|
||||
mode,
|
||||
isOpen,
|
||||
onClose,
|
||||
table,
|
||||
row,
|
||||
rowIds,
|
||||
onSuccess,
|
||||
}: TableRowModalProps) {
|
||||
const params = useParams()
|
||||
const workspaceId = params.workspaceId as string
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
* @module tables/[tableId]/table-data-viewer/components
|
||||
*/
|
||||
|
||||
export * from './cell-renderer'
|
||||
export * from './cell-viewer-modal'
|
||||
export * from './pagination'
|
||||
export * from './row-context-menu'
|
||||
export * from './schema-viewer-modal'
|
||||
export * from './table-body-states'
|
||||
export * from './table-cell-renderer'
|
||||
export * from './table-header-bar'
|
||||
export * from './table-pagination'
|
||||
|
||||
@@ -9,14 +9,14 @@ import { Button, TableCell, TableRow } from '@/components/emcn'
|
||||
import { Skeleton } from '@/components/ui/skeleton'
|
||||
import type { ColumnDefinition } from '@/lib/table'
|
||||
|
||||
interface LoadingRowsProps {
|
||||
interface TableLoadingRowsProps {
|
||||
columns: ColumnDefinition[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders skeleton rows while table data is loading.
|
||||
*/
|
||||
export function LoadingRows({ columns }: LoadingRowsProps) {
|
||||
export function TableLoadingRows({ columns }: TableLoadingRowsProps) {
|
||||
return (
|
||||
<>
|
||||
{Array.from({ length: 25 }).map((_, rowIndex) => (
|
||||
@@ -52,7 +52,7 @@ export function LoadingRows({ columns }: LoadingRowsProps) {
|
||||
)
|
||||
}
|
||||
|
||||
interface EmptyRowsProps {
|
||||
interface TableEmptyRowsProps {
|
||||
columnCount: number
|
||||
hasFilter: boolean
|
||||
onAddRow: () => void
|
||||
@@ -61,7 +61,7 @@ interface EmptyRowsProps {
|
||||
/**
|
||||
* Renders an empty state when no rows are present.
|
||||
*/
|
||||
export function EmptyRows({ columnCount, hasFilter, onAddRow }: EmptyRowsProps) {
|
||||
export function TableEmptyRows({ columnCount, hasFilter, onAddRow }: TableEmptyRowsProps) {
|
||||
return (
|
||||
<TableRow>
|
||||
<TableCell colSpan={columnCount + 1} className='h-[160px] text-center'>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
/**
|
||||
* Cell value renderer for different column types.
|
||||
*
|
||||
* @module tables/[tableId]/table-data-viewer/components/cell-renderer
|
||||
* @module tables/[tableId]/table-data-viewer/components/table-cell-renderer
|
||||
*/
|
||||
|
||||
import type { ColumnDefinition } from '@/lib/table'
|
||||
import { STRING_TRUNCATE_LENGTH } from '../constants'
|
||||
import type { CellViewerData } from '../types'
|
||||
|
||||
interface CellRendererProps {
|
||||
interface TableCellRendererProps {
|
||||
value: unknown
|
||||
column: ColumnDefinition
|
||||
onCellClick: (columnName: string, value: unknown, type: CellViewerData['type']) => void
|
||||
@@ -20,7 +20,7 @@ interface CellRendererProps {
|
||||
* @param props - Component props
|
||||
* @returns Formatted cell content
|
||||
*/
|
||||
export function CellRenderer({ value, column, onCellClick }: CellRendererProps) {
|
||||
export function TableCellRenderer({ value, column, onCellClick }: TableCellRendererProps) {
|
||||
const isNull = value === null || value === undefined
|
||||
|
||||
if (isNull) {
|
||||
@@ -1,12 +1,12 @@
|
||||
/**
|
||||
* Pagination controls for the table.
|
||||
*
|
||||
* @module tables/[tableId]/table-data-viewer/components/pagination
|
||||
* @module tables/[tableId]/table-data-viewer/components/table-pagination
|
||||
*/
|
||||
|
||||
import { Button } from '@/components/emcn'
|
||||
|
||||
interface PaginationProps {
|
||||
interface TablePaginationProps {
|
||||
currentPage: number
|
||||
totalPages: number
|
||||
totalCount: number
|
||||
@@ -18,15 +18,15 @@ interface PaginationProps {
|
||||
* Renders pagination controls for navigating table pages.
|
||||
*
|
||||
* @param props - Component props
|
||||
* @returns Pagination controls or null if only one page
|
||||
* @returns Table pagination controls or null if only one page
|
||||
*/
|
||||
export function Pagination({
|
||||
export function TablePagination({
|
||||
currentPage,
|
||||
totalPages,
|
||||
totalCount,
|
||||
onPreviousPage,
|
||||
onNextPage,
|
||||
}: PaginationProps) {
|
||||
}: TablePaginationProps) {
|
||||
if (totalPages <= 1) return null
|
||||
|
||||
return (
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import type { QueryOptions } from '../../components/filter-builder'
|
||||
import type { QueryOptions } from '../../components/table-query-builder'
|
||||
import { ROWS_PER_PAGE } from '../constants'
|
||||
import type { TableData, TableRowData } from '../types'
|
||||
|
||||
|
||||
@@ -19,16 +19,16 @@ import {
|
||||
TableRow,
|
||||
} from '@/components/emcn'
|
||||
import { cn } from '@/lib/core/utils/cn'
|
||||
import { FilterBuilder, type QueryOptions, RowModal, TableActionBar } from '../components'
|
||||
import { type QueryOptions, TableActionBar, TableQueryBuilder, TableRowModal } from '../components'
|
||||
import {
|
||||
CellRenderer,
|
||||
CellViewerModal,
|
||||
EmptyRows,
|
||||
LoadingRows,
|
||||
Pagination,
|
||||
RowContextMenu,
|
||||
SchemaViewerModal,
|
||||
TableCellRenderer,
|
||||
TableEmptyRows,
|
||||
TableHeaderBar,
|
||||
TableLoadingRows,
|
||||
TablePagination,
|
||||
} from './components'
|
||||
import { useContextMenu, useRowSelection, useTableData } from './hooks'
|
||||
import type { CellViewerData, TableRowData } from './types'
|
||||
@@ -199,7 +199,7 @@ export function TableDataViewer() {
|
||||
/>
|
||||
|
||||
<div className='flex shrink-0 flex-col gap-[8px] border-[var(--border)] border-b px-[16px] py-[10px]'>
|
||||
<FilterBuilder
|
||||
<TableQueryBuilder
|
||||
columns={columns}
|
||||
onApply={handleApplyQueryOptions}
|
||||
onAddRow={handleAddRow}
|
||||
@@ -241,9 +241,9 @@ export function TableDataViewer() {
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{isLoadingRows ? (
|
||||
<LoadingRows columns={columns} />
|
||||
<TableLoadingRows columns={columns} />
|
||||
) : rows.length === 0 ? (
|
||||
<EmptyRows
|
||||
<TableEmptyRows
|
||||
columnCount={columns.length}
|
||||
hasFilter={!!queryOptions.filter}
|
||||
onAddRow={handleAddRow}
|
||||
@@ -268,7 +268,7 @@ export function TableDataViewer() {
|
||||
{columns.map((column) => (
|
||||
<TableCell key={column.name}>
|
||||
<div className='max-w-[300px] truncate text-[13px]'>
|
||||
<CellRenderer
|
||||
<TableCellRenderer
|
||||
value={row.data[column.name]}
|
||||
column={column}
|
||||
onCellClick={handleCellClick}
|
||||
@@ -283,7 +283,7 @@ export function TableDataViewer() {
|
||||
</Table>
|
||||
</div>
|
||||
|
||||
<Pagination
|
||||
<TablePagination
|
||||
currentPage={currentPage}
|
||||
totalPages={totalPages}
|
||||
totalCount={totalCount}
|
||||
@@ -291,7 +291,7 @@ export function TableDataViewer() {
|
||||
onNextPage={() => setCurrentPage((p) => Math.min(totalPages - 1, p + 1))}
|
||||
/>
|
||||
|
||||
<RowModal
|
||||
<TableRowModal
|
||||
mode='add'
|
||||
isOpen={showAddModal}
|
||||
onClose={() => setShowAddModal(false)}
|
||||
@@ -303,7 +303,7 @@ export function TableDataViewer() {
|
||||
/>
|
||||
|
||||
{editingRow && (
|
||||
<RowModal
|
||||
<TableRowModal
|
||||
mode='edit'
|
||||
isOpen={true}
|
||||
onClose={() => setEditingRow(null)}
|
||||
@@ -317,7 +317,7 @@ export function TableDataViewer() {
|
||||
)}
|
||||
|
||||
{deletingRows.length > 0 && (
|
||||
<RowModal
|
||||
<TableRowModal
|
||||
mode='delete'
|
||||
isOpen={true}
|
||||
onClose={() => setDeletingRows([])}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Hook for filter builder functionality.
|
||||
*
|
||||
* Provides reusable filter condition management logic shared between
|
||||
* the table data viewer's FilterBuilder and workflow block's FilterFormat.
|
||||
* the table data viewer's TableQueryBuilder and workflow block's FilterFormat.
|
||||
*/
|
||||
|
||||
import { useCallback, useMemo } from 'react'
|
||||
|
||||
Reference in New Issue
Block a user