From 2de52416d477edd84cdb37b66ec83cbd1c9a20ba Mon Sep 17 00:00:00 2001 From: Emir Karabeg Date: Tue, 18 Feb 2025 13:43:26 -0800 Subject: [PATCH] feat(table): dropdown tags and envvar --- .../components/sub-block/components/table.tsx | 151 +++++++++++++++--- 1 file changed, 125 insertions(+), 26 deletions(-) diff --git a/app/w/[id]/components/workflow-block/components/sub-block/components/table.tsx b/app/w/[id]/components/workflow-block/components/sub-block/components/table.tsx index 0849fa8f6..231792899 100644 --- a/app/w/[id]/components/workflow-block/components/sub-block/components/table.tsx +++ b/app/w/[id]/components/workflow-block/components/sub-block/components/table.tsx @@ -1,7 +1,9 @@ -import { useEffect, useMemo, useRef } from 'react' +import { useEffect, useMemo, useRef, useState } from 'react' import { Trash2 } from 'lucide-react' import { Button } from '@/components/ui/button' +import { EnvVarDropdown, checkEnvVarTrigger } from '@/components/ui/env-var-dropdown' import { Input } from '@/components/ui/input' +import { TagDropdown, checkTagTrigger } from '@/components/ui/tag-dropdown' import { cn } from '@/lib/utils' import { useSubBlockValue } from '../hooks/use-sub-block-value' @@ -32,6 +34,17 @@ export function Table({ columns, blockId, subBlockId }: TableProps) { return value as TableRow[] }, [value, columns]) + // Add state for managing dropdowns + const [activeCell, setActiveCell] = useState<{ + rowIndex: number + column: string + showEnvVars: boolean + showTags: boolean + cursorPosition: number + activeSourceBlockId: string | null + element?: HTMLElement | null + } | null>(null) + const handleCellChange = (rowIndex: number, column: string, value: string) => { const updatedRows = [...rows].map((row, idx) => idx === rowIndex @@ -75,19 +88,61 @@ export function Table({ columns, blockId, subBlockId }: TableProps) { ) - const renderCell = (row: TableRow, rowIndex: number, column: string, cellIndex: number) => ( - - handleCellChange(rowIndex, column, e.target.value)} - className="border-0 focus-visible:ring-0 focus-visible:ring-offset-0 text-muted-foreground placeholder:text-muted-foreground/50" - /> - - ) + const renderCell = (row: TableRow, rowIndex: number, column: string, cellIndex: number) => { + return ( + + { + const newValue = e.target.value + const cursorPosition = e.target.selectionStart ?? 0 + + handleCellChange(rowIndex, column, newValue) + + // Check for triggers + const envVarTrigger = checkEnvVarTrigger(newValue, cursorPosition) + const tagTrigger = checkTagTrigger(newValue, cursorPosition) + + setActiveCell({ + rowIndex, + column, + showEnvVars: envVarTrigger.show, + showTags: tagTrigger.show, + cursorPosition, + activeSourceBlockId: null, + element: e.target, + }) + }} + onFocus={(e) => { + setActiveCell({ + rowIndex, + column, + showEnvVars: false, + showTags: false, + cursorPosition: 0, + activeSourceBlockId: null, + element: e.target, + }) + }} + onBlur={() => { + setTimeout(() => { + setActiveCell(null) + }, 200) + }} + onKeyDown={(e) => { + if (e.key === 'Escape') { + setActiveCell(null) + } + }} + className="border-0 focus-visible:ring-0 focus-visible:ring-offset-0 text-muted-foreground placeholder:text-muted-foreground/50" + /> + + ) + } const renderDeleteButton = (rowIndex: number) => rows.length > 1 && ( @@ -104,18 +159,62 @@ export function Table({ columns, blockId, subBlockId }: TableProps) { ) return ( -
- - {renderHeader()} - - {rows.map((row, rowIndex) => ( - - {columns.map((column, cellIndex) => renderCell(row, rowIndex, column, cellIndex))} - {renderDeleteButton(rowIndex)} - - ))} - -
+
+
+ + {renderHeader()} + + {rows.map((row, rowIndex) => ( + + {columns.map((column, cellIndex) => renderCell(row, rowIndex, column, cellIndex))} + {renderDeleteButton(rowIndex)} + + ))} + +
+
+ + {activeCell?.element && ( + <> + { + handleCellChange(activeCell.rowIndex, activeCell.column, newValue) + setActiveCell(null) + }} + searchTerm={ + activeCell.showEnvVars + ? rows[activeCell.rowIndex].cells[activeCell.column] + .slice(activeCell.cursorPosition - 2) + .match(/\{\{(\w*)$/)?.[1] || '' + : '' + } + inputValue={rows[activeCell.rowIndex].cells[activeCell.column] || ''} + cursorPosition={activeCell.cursorPosition} + onClose={() => { + setActiveCell((prev) => (prev ? { ...prev, showEnvVars: false } : null)) + }} + className="w-[200px] absolute" + /> + { + handleCellChange(activeCell.rowIndex, activeCell.column, newValue) + setActiveCell(null) + }} + blockId={blockId} + activeSourceBlockId={activeCell.activeSourceBlockId} + inputValue={rows[activeCell.rowIndex].cells[activeCell.column] || ''} + cursorPosition={activeCell.cursorPosition} + onClose={() => { + setActiveCell((prev) => + prev ? { ...prev, showTags: false, activeSourceBlockId: null } : null + ) + }} + className="w-[200px] absolute" + /> + + )}
) }