mirror of
https://github.com/simstudioai/sim.git
synced 2026-04-06 03:00:16 -04:00
updates
This commit is contained in:
@@ -1,9 +1,3 @@
|
||||
/**
|
||||
* Table data viewer components.
|
||||
*
|
||||
* @module tables/[tableId]/components
|
||||
*/
|
||||
|
||||
export * from './table-action-bar'
|
||||
export * from './table-query-builder'
|
||||
export * from './table-row-modal'
|
||||
|
||||
@@ -3,33 +3,18 @@
|
||||
import { Trash2, X } from 'lucide-react'
|
||||
import { Button } from '@/components/emcn'
|
||||
|
||||
/**
|
||||
* Props for the TableActionBar component.
|
||||
*/
|
||||
interface TableActionBarProps {
|
||||
/** Number of currently selected rows */
|
||||
selectedCount: number
|
||||
/** Callback when delete action is triggered */
|
||||
onDelete: () => void
|
||||
/** Callback when selection should be cleared */
|
||||
onClearSelection: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Action bar displayed when rows are selected in the table.
|
||||
*
|
||||
* @remarks
|
||||
* Shows the count of selected rows and provides actions for
|
||||
* bulk operations like deletion.
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* <TableActionBar
|
||||
* selectedCount={selectedRows.size}
|
||||
* onDelete={handleDeleteSelected}
|
||||
* onClearSelection={() => setSelectedRows(new Set())}
|
||||
* />
|
||||
* ```
|
||||
*/
|
||||
export function TableActionBar({ selectedCount, onDelete, onClearSelection }: TableActionBarProps) {
|
||||
return (
|
||||
|
||||
@@ -9,13 +9,8 @@ import { useFilterBuilder } from '@/lib/table/filters/use-builder'
|
||||
import { conditionsToFilter } from '@/lib/table/filters/utils'
|
||||
import type { JsonValue } from '@/lib/table/types'
|
||||
|
||||
/**
|
||||
* Query options for the table API.
|
||||
*/
|
||||
export interface QueryOptions {
|
||||
/** Filter criteria or null for no filter, keys are column names, values are filter values */
|
||||
filter: Record<string, JsonValue> | null
|
||||
/** Sort configuration or null for default sort */
|
||||
sort: SortCondition | null
|
||||
}
|
||||
|
||||
@@ -46,19 +41,10 @@ interface TableQueryBuilderProps {
|
||||
/**
|
||||
* Component for building filter and sort queries for table data.
|
||||
*
|
||||
* @remarks
|
||||
* Provides a visual interface for:
|
||||
* - Adding multiple filter conditions with AND/OR logic
|
||||
* - Configuring sort column and direction
|
||||
* - Applying or clearing the query
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* <TableQueryBuilder
|
||||
* columns={tableColumns}
|
||||
* onApply={(options) => setQueryOptions(options)}
|
||||
* onAddRow={() => setShowAddModal(true)}
|
||||
* />
|
||||
* ```
|
||||
*/
|
||||
export function TableQueryBuilder({
|
||||
@@ -89,9 +75,6 @@ export function TableQueryBuilder({
|
||||
setConditions,
|
||||
})
|
||||
|
||||
/**
|
||||
* Adds a sort condition.
|
||||
*/
|
||||
const handleAddSort = useCallback(() => {
|
||||
setSortCondition({
|
||||
id: nanoid(),
|
||||
@@ -100,16 +83,10 @@ export function TableQueryBuilder({
|
||||
})
|
||||
}, [columns])
|
||||
|
||||
/**
|
||||
* Removes the sort condition.
|
||||
*/
|
||||
const handleRemoveSort = useCallback(() => {
|
||||
setSortCondition(null)
|
||||
}, [])
|
||||
|
||||
/**
|
||||
* Applies the current filter and sort conditions.
|
||||
*/
|
||||
const handleApply = useCallback(() => {
|
||||
const filter = conditionsToFilter(conditions)
|
||||
onApply({
|
||||
@@ -118,9 +95,6 @@ export function TableQueryBuilder({
|
||||
})
|
||||
}, [conditions, sortCondition, onApply])
|
||||
|
||||
/**
|
||||
* Clears all filters and sort conditions.
|
||||
*/
|
||||
const handleClear = useCallback(() => {
|
||||
setConditions([])
|
||||
setSortCondition(null)
|
||||
|
||||
@@ -20,35 +20,19 @@ import type { ColumnDefinition, TableRow, TableSchema } from '@/lib/table'
|
||||
|
||||
const logger = createLogger('TableRowModal')
|
||||
|
||||
/**
|
||||
* Table metadata needed for row operations.
|
||||
*/
|
||||
export interface TableInfo {
|
||||
/** Unique identifier for the table */
|
||||
id: string
|
||||
/** Table name for display */
|
||||
name: string
|
||||
/** Schema defining columns */
|
||||
schema: TableSchema
|
||||
}
|
||||
|
||||
/**
|
||||
* Props for the TableRowModal component.
|
||||
*/
|
||||
export interface TableRowModalProps {
|
||||
/** The operation mode */
|
||||
mode: 'add' | 'edit' | 'delete'
|
||||
/** Whether the modal is open */
|
||||
isOpen: boolean
|
||||
/** Callback when the modal should close */
|
||||
onClose: () => void
|
||||
/** Table to operate on */
|
||||
table: TableInfo
|
||||
/** Row being edited/deleted (required for edit/delete modes) */
|
||||
row?: TableRow
|
||||
/** Row IDs to delete (for delete mode batch operations) */
|
||||
rowIds?: string[]
|
||||
/** Callback when operation is successful */
|
||||
onSuccess: () => void
|
||||
}
|
||||
|
||||
@@ -67,9 +51,6 @@ function createInitialRowData(columns: ColumnDefinition[]): Record<string, unkno
|
||||
return initial
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans and transforms form data for API submission.
|
||||
*/
|
||||
function cleanRowData(
|
||||
columns: ColumnDefinition[],
|
||||
rowData: Record<string, unknown>
|
||||
@@ -104,9 +85,6 @@ function cleanRowData(
|
||||
return cleanData
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a value for display in the input field.
|
||||
*/
|
||||
function formatValueForInput(value: unknown, type: string): string {
|
||||
if (value === null || value === undefined) return ''
|
||||
if (type === 'json') {
|
||||
@@ -123,44 +101,6 @@ function formatValueForInput(value: unknown, type: string): string {
|
||||
return String(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Unified modal component for add, edit, and delete row operations.
|
||||
*
|
||||
* @example Add mode:
|
||||
* ```tsx
|
||||
* <TableRowModal
|
||||
* mode="add"
|
||||
* isOpen={isOpen}
|
||||
* onClose={() => setIsOpen(false)}
|
||||
* table={tableData}
|
||||
* onSuccess={() => refetchRows()}
|
||||
* />
|
||||
* ```
|
||||
*
|
||||
* @example Edit mode:
|
||||
* ```tsx
|
||||
* <TableRowModal
|
||||
* mode="edit"
|
||||
* isOpen={isOpen}
|
||||
* onClose={() => setIsOpen(false)}
|
||||
* table={tableData}
|
||||
* row={selectedRow}
|
||||
* onSuccess={() => refetchRows()}
|
||||
* />
|
||||
* ```
|
||||
*
|
||||
* @example Delete mode:
|
||||
* ```tsx
|
||||
* <TableRowModal
|
||||
* mode="delete"
|
||||
* isOpen={isOpen}
|
||||
* onClose={() => setIsOpen(false)}
|
||||
* table={tableData}
|
||||
* rowIds={selectedRowIds}
|
||||
* onSuccess={() => refetchRows()}
|
||||
* />
|
||||
* ```
|
||||
*/
|
||||
export function TableRowModal({
|
||||
mode,
|
||||
isOpen,
|
||||
@@ -191,9 +131,6 @@ export function TableRowModal({
|
||||
}
|
||||
}, [isOpen, mode, columns, row])
|
||||
|
||||
/**
|
||||
* Handles add/edit form submission.
|
||||
*/
|
||||
const handleFormSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault()
|
||||
setError(null)
|
||||
@@ -277,9 +214,6 @@ export function TableRowModal({
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles modal close and resets state.
|
||||
*/
|
||||
const handleClose = () => {
|
||||
setRowData({})
|
||||
setError(null)
|
||||
@@ -338,7 +272,6 @@ export function TableRowModal({
|
||||
)
|
||||
}
|
||||
|
||||
// Add/Edit mode UI
|
||||
const isAddMode = mode === 'add'
|
||||
|
||||
return (
|
||||
@@ -410,21 +343,12 @@ function ErrorMessage({ error }: { error: string | null }) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Props for the ColumnField component.
|
||||
*/
|
||||
interface ColumnFieldProps {
|
||||
/** Column definition */
|
||||
column: ColumnDefinition
|
||||
/** Current field value */
|
||||
value: unknown
|
||||
/** Callback when value changes */
|
||||
onChange: (value: unknown) => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders an input field for a column based on its type.
|
||||
*/
|
||||
function ColumnField({ column, value, onChange }: ColumnFieldProps) {
|
||||
return (
|
||||
<div className='flex flex-col gap-[8px]'>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
/**
|
||||
* Modal for viewing cell details.
|
||||
*
|
||||
* @module tables/[tableId]/table-data-viewer/components/cell-viewer-modal
|
||||
*/
|
||||
|
||||
import { Copy, X } from 'lucide-react'
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
/**
|
||||
* Table data viewer sub-components.
|
||||
*
|
||||
* @module tables/[tableId]/table-data-viewer/components
|
||||
*/
|
||||
|
||||
export * from './cell-viewer-modal'
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
/**
|
||||
* Context menu for row actions.
|
||||
*
|
||||
* @module tables/[tableId]/table-data-viewer/components/row-context-menu
|
||||
*/
|
||||
|
||||
import { Edit, Trash2 } from 'lucide-react'
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
/**
|
||||
* Modal for viewing table schema.
|
||||
*
|
||||
* @module tables/[tableId]/table-data-viewer/components/schema-viewer-modal
|
||||
*/
|
||||
|
||||
import { Info, X } from 'lucide-react'
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
/**
|
||||
* Table body placeholder states (loading and empty).
|
||||
*
|
||||
* @module tables/[tableId]/table-data-viewer/components/table-body-states
|
||||
*/
|
||||
|
||||
import { Plus } from 'lucide-react'
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
/**
|
||||
* Cell value renderer for different column types.
|
||||
*
|
||||
* @module tables/[tableId]/table-data-viewer/components/table-cell-renderer
|
||||
*/
|
||||
|
||||
import type { ColumnDefinition } from '@/lib/table'
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
/**
|
||||
* Header bar for the table data viewer.
|
||||
*
|
||||
* @module tables/[tableId]/table-data-viewer/components/table-header-bar
|
||||
*/
|
||||
|
||||
import { Info, RefreshCw } from 'lucide-react'
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
/**
|
||||
* Pagination controls for the table.
|
||||
*
|
||||
* @module tables/[tableId]/table-data-viewer/components/table-pagination
|
||||
*/
|
||||
|
||||
import { Button } from '@/components/emcn'
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
/**
|
||||
* Constants for the table data viewer.
|
||||
*
|
||||
* @module tables/[tableId]/table-data-viewer/constants
|
||||
*/
|
||||
|
||||
/** Number of rows to fetch per page */
|
||||
export const ROWS_PER_PAGE = 100
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
/**
|
||||
* Custom hooks for the table data viewer.
|
||||
*
|
||||
* @module tables/[tableId]/table-data-viewer/hooks
|
||||
*/
|
||||
|
||||
export * from './use-context-menu'
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
/**
|
||||
* Hook for managing context menu state.
|
||||
*
|
||||
* @module tables/[tableId]/table-data-viewer/hooks/use-context-menu
|
||||
*/
|
||||
|
||||
import { useCallback, useState } from 'react'
|
||||
import type { TableRow } from '@/lib/table'
|
||||
import type { ContextMenuState } from '../types'
|
||||
@@ -26,9 +20,6 @@ export function useContextMenu(): UseContextMenuReturn {
|
||||
row: null,
|
||||
})
|
||||
|
||||
/**
|
||||
* Opens the context menu for a row.
|
||||
*/
|
||||
const handleRowContextMenu = useCallback((e: React.MouseEvent, row: TableRow) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
@@ -39,9 +30,6 @@ export function useContextMenu(): UseContextMenuReturn {
|
||||
})
|
||||
}, [])
|
||||
|
||||
/**
|
||||
* Closes the context menu.
|
||||
*/
|
||||
const closeContextMenu = useCallback(() => {
|
||||
setContextMenu((prev) => ({ ...prev, isOpen: false }))
|
||||
}, [])
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
/**
|
||||
* Hook for managing row selection state.
|
||||
*
|
||||
* @module tables/[tableId]/table-data-viewer/hooks/use-row-selection
|
||||
*/
|
||||
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
/**
|
||||
* Hook for fetching table data and rows.
|
||||
*
|
||||
* @module tables/[tableId]/table-data-viewer/hooks/use-table-data
|
||||
*/
|
||||
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
|
||||
@@ -1,8 +1,2 @@
|
||||
/**
|
||||
* Table data viewer module.
|
||||
*
|
||||
* @module tables/[tableId]/table-data-viewer
|
||||
*/
|
||||
|
||||
export * from './table-data-viewer'
|
||||
export * from './types'
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
'use client'
|
||||
|
||||
/**
|
||||
* Main table data viewer component.
|
||||
*
|
||||
* @module tables/[tableId]/table-data-viewer/table-data-viewer
|
||||
*/
|
||||
|
||||
import { useCallback, useState } from 'react'
|
||||
import { useParams, useRouter } from 'next/navigation'
|
||||
import {
|
||||
@@ -37,17 +31,11 @@ import type { CellViewerData } from './types'
|
||||
/**
|
||||
* Main component for viewing and managing table data.
|
||||
*
|
||||
* @remarks
|
||||
* Provides functionality for:
|
||||
* - Viewing rows with pagination
|
||||
* - Filtering and sorting
|
||||
* - Adding, editing, and deleting rows
|
||||
* - Viewing cell details for long/complex values
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* <TableDataViewer />
|
||||
* ```
|
||||
*/
|
||||
export function TableDataViewer() {
|
||||
const params = useParams()
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
/**
|
||||
* Type definitions for the table data viewer.
|
||||
*
|
||||
* @module tables/[tableId]/table-data-viewer/types
|
||||
*/
|
||||
|
||||
import type { TableRow } from '@/lib/table'
|
||||
@@ -15,7 +13,7 @@ export interface CellViewerData {
|
||||
/** Value being displayed */
|
||||
value: unknown
|
||||
/** Display type for formatting */
|
||||
type: 'json' | 'text' | 'date'
|
||||
type: 'json' | 'text' | 'date' | 'boolean' | 'number'
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
/**
|
||||
* Utility functions for the table data viewer.
|
||||
*
|
||||
* @module tables/[tableId]/table-data-viewer/utils
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the badge variant for a column type.
|
||||
*
|
||||
|
||||
@@ -23,19 +23,11 @@ import { useCreateTable } from '@/hooks/queries/use-tables'
|
||||
|
||||
const logger = createLogger('CreateTableModal')
|
||||
|
||||
/**
|
||||
* Props for the CreateTableModal component.
|
||||
*/
|
||||
interface CreateTableModalProps {
|
||||
/** Whether the modal is open */
|
||||
isOpen: boolean
|
||||
/** Callback when the modal should close */
|
||||
onClose: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Available column type options for the combobox UI.
|
||||
*/
|
||||
const COLUMN_TYPE_OPTIONS: Array<{ value: ColumnDefinition['type']; label: string }> = [
|
||||
{ value: 'string', label: 'String' },
|
||||
{ value: 'number', label: 'Number' },
|
||||
@@ -44,9 +36,6 @@ const COLUMN_TYPE_OPTIONS: Array<{ value: ColumnDefinition['type']; label: strin
|
||||
{ value: 'json', label: 'JSON' },
|
||||
]
|
||||
|
||||
/**
|
||||
* Column definition with a stable ID for React key.
|
||||
*/
|
||||
interface ColumnWithId extends ColumnDefinition {
|
||||
/** Stable ID for React key */
|
||||
id: string
|
||||
@@ -59,23 +48,6 @@ function createEmptyColumn(): ColumnWithId {
|
||||
return { id: nanoid(), name: '', type: 'string', required: true, unique: false }
|
||||
}
|
||||
|
||||
/**
|
||||
* Modal component for creating a new table in a workspace.
|
||||
*
|
||||
* @remarks
|
||||
* This modal allows users to:
|
||||
* - Set a table name and description
|
||||
* - Define columns with name, type, and constraints
|
||||
* - Create the table via the API
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* <CreateTableModal
|
||||
* isOpen={isModalOpen}
|
||||
* onClose={() => setIsModalOpen(false)}
|
||||
* />
|
||||
* ```
|
||||
*/
|
||||
export function CreateTableModal({ isOpen, onClose }: CreateTableModalProps) {
|
||||
const params = useParams()
|
||||
const workspaceId = params.workspaceId as string
|
||||
|
||||
@@ -1,7 +1,2 @@
|
||||
/**
|
||||
* Table management components.
|
||||
*
|
||||
* @module tables/components
|
||||
*/
|
||||
export * from './create-table-modal'
|
||||
export * from './table-card'
|
||||
|
||||
@@ -26,94 +26,21 @@ import {
|
||||
} from '@/components/emcn'
|
||||
import type { TableDefinition } from '@/lib/table'
|
||||
import { useDeleteTable } from '@/hooks/queries/use-tables'
|
||||
import { getTypeBadgeVariant } from '../[tableId]/table-data-viewer/utils'
|
||||
import { formatAbsoluteDate, formatRelativeTime } from './utils'
|
||||
|
||||
const logger = createLogger('TableCard')
|
||||
|
||||
/**
|
||||
* Props for the TableCard component.
|
||||
*/
|
||||
interface TableCardProps {
|
||||
/** The table definition to display */
|
||||
table: TableDefinition
|
||||
/** ID of the workspace containing this table */
|
||||
workspaceId: string
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a date to relative time (e.g., "2h ago", "3d ago").
|
||||
*
|
||||
* @param dateValue - Date string or Date object to format
|
||||
* @returns Human-readable relative time string
|
||||
*/
|
||||
function formatRelativeTime(dateValue: string | Date): string {
|
||||
const dateString = typeof dateValue === 'string' ? dateValue : dateValue.toISOString()
|
||||
const date = new Date(dateString)
|
||||
const now = new Date()
|
||||
const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000)
|
||||
|
||||
if (diffInSeconds < 60) return 'just now'
|
||||
if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`
|
||||
if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`
|
||||
if (diffInSeconds < 604800) return `${Math.floor(diffInSeconds / 86400)}d ago`
|
||||
if (diffInSeconds < 2592000) return `${Math.floor(diffInSeconds / 604800)}w ago`
|
||||
if (diffInSeconds < 31536000) return `${Math.floor(diffInSeconds / 2592000)}mo ago`
|
||||
return `${Math.floor(diffInSeconds / 31536000)}y ago`
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a date to absolute format for tooltip display.
|
||||
*
|
||||
* @param dateValue - Date string or Date object to format
|
||||
* @returns Formatted date string (e.g., "Jan 15, 2024, 10:30 AM")
|
||||
*/
|
||||
function formatAbsoluteDate(dateValue: string | Date): string {
|
||||
const dateString = typeof dateValue === 'string' ? dateValue : dateValue.toISOString()
|
||||
const date = new Date(dateString)
|
||||
return date.toLocaleDateString('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the badge variant for a column type.
|
||||
*
|
||||
* @param type - The column type
|
||||
* @returns Badge variant name
|
||||
*/
|
||||
function getTypeBadgeVariant(
|
||||
type: string
|
||||
): 'green' | 'blue' | 'purple' | 'orange' | 'teal' | 'gray' {
|
||||
switch (type) {
|
||||
case 'string':
|
||||
return 'green'
|
||||
case 'number':
|
||||
return 'blue'
|
||||
case 'boolean':
|
||||
return 'purple'
|
||||
case 'json':
|
||||
return 'orange'
|
||||
case 'date':
|
||||
return 'teal'
|
||||
default:
|
||||
return 'gray'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Card component for displaying a table summary.
|
||||
*
|
||||
* @remarks
|
||||
* Shows table name, column/row counts, description, and provides
|
||||
* actions for viewing schema and deleting the table.
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* <TableCard table={tableData} workspaceId="ws_123" />
|
||||
* ```
|
||||
*/
|
||||
export function TableCard({ table, workspaceId }: TableCardProps) {
|
||||
const router = useRouter()
|
||||
@@ -123,9 +50,6 @@ export function TableCard({ table, workspaceId }: TableCardProps) {
|
||||
|
||||
const deleteTable = useDeleteTable(workspaceId)
|
||||
|
||||
/**
|
||||
* Handles table deletion.
|
||||
*/
|
||||
const handleDelete = async () => {
|
||||
try {
|
||||
await deleteTable.mutateAsync(table.id)
|
||||
@@ -135,9 +59,6 @@ export function TableCard({ table, workspaceId }: TableCardProps) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Navigates to the table detail page.
|
||||
*/
|
||||
const navigateToTable = () => {
|
||||
router.push(`/workspace/${workspaceId}/tables/${table.id}`)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
export function formatRelativeTime(dateValue: string | Date): string {
|
||||
const dateString = typeof dateValue === 'string' ? dateValue : dateValue.toISOString()
|
||||
const date = new Date(dateString)
|
||||
const now = new Date()
|
||||
const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000)
|
||||
|
||||
if (diffInSeconds < 60) return 'just now'
|
||||
if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`
|
||||
if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`
|
||||
if (diffInSeconds < 604800) return `${Math.floor(diffInSeconds / 86400)}d ago`
|
||||
if (diffInSeconds < 2592000) return `${Math.floor(diffInSeconds / 604800)}w ago`
|
||||
if (diffInSeconds < 31536000) return `${Math.floor(diffInSeconds / 2592000)}mo ago`
|
||||
return `${Math.floor(diffInSeconds / 31536000)}y ago`
|
||||
}
|
||||
|
||||
export function formatAbsoluteDate(dateValue: string | Date): string {
|
||||
const dateString = typeof dateValue === 'string' ? dateValue : dateValue.toISOString()
|
||||
const date = new Date(dateString)
|
||||
return date.toLocaleDateString('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
})
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
/**
|
||||
* Limits and constants for user-defined tables.
|
||||
*
|
||||
* @module lib/table/constants
|
||||
*/
|
||||
|
||||
export const TABLE_LIMITS = {
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
/**
|
||||
* Shared constants and types for table filtering and sorting.
|
||||
*
|
||||
* @module lib/table/filters/constants
|
||||
*
|
||||
*/
|
||||
|
||||
/** Comparison operators for filter conditions (maps to query-builder.ts) */
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
/**
|
||||
* Filter utilities for table queries.
|
||||
*
|
||||
* @module lib/table/filters
|
||||
*/
|
||||
|
||||
export * from './constants'
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
/**
|
||||
* Shared utilities for filter builder UI components.
|
||||
*
|
||||
* @module lib/table/filters/utils
|
||||
*/
|
||||
|
||||
import { nanoid } from 'nanoid'
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
*
|
||||
* Hooks are not re-exported here to avoid pulling React into server code.
|
||||
* Import hooks directly from '@/lib/table/hooks' in client components.
|
||||
*
|
||||
* @module lib/table
|
||||
*/
|
||||
|
||||
export * from './constants'
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
*
|
||||
* Provides functions to enrich tool descriptions and parameter schemas
|
||||
* with table-specific information so LLMs can construct proper queries.
|
||||
*
|
||||
* @module lib/table/llm-enrichment
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
* Use API routes for: HTTP requests, frontend clients.
|
||||
*
|
||||
* Note: API routes have their own implementations for HTTP-specific concerns.
|
||||
*
|
||||
* @module lib/table/service
|
||||
*/
|
||||
|
||||
import { db } from '@sim/db'
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
/**
|
||||
* Core type definitions for user-defined tables.
|
||||
*
|
||||
* @module lib/table/types
|
||||
*/
|
||||
|
||||
import type { COLUMN_TYPES } from './constants'
|
||||
|
||||
Reference in New Issue
Block a user