Skip to content
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
7c5b6ea
Workflow_Execution_Working
Sep 3, 2025
810347d
Added_email_support
Sep 3, 2025
e429f33
landing-page-v2
debajyoti0606 Sep 3, 2025
81b1f69
Server_Running_After_Rebase
Sep 4, 2025
4e7e012
UI_Fixes_BE_apis
Sep 8, 2025
547e025
Email_Testing_Done
Sep 9, 2025
1a0889b
Email_Testing_Done
Sep 9, 2025
619da55
use_input_instead_of_latest
Sep 9, 2025
5a2a2db
executed-enhance
debajyoti0606 Sep 9, 2025
25b475d
executed-enhance-v2
debajyoti0606 Sep 9, 2025
3dc10ad
executed-enhance-v2
debajyoti0606 Sep 9, 2025
ce7558d
improve-UX
debajyoti0606 Sep 9, 2025
9b492e7
Added Complex Create Template api and improved connections
avirupsinha12 Sep 9, 2025
7943d80
merged-executed-page
debajyoti0606 Sep 10, 2025
6c057d4
Added Additional UI fixes for Node connections and Edges
avirupsinha12 Sep 10, 2025
fa1463f
minor-bug-fixes
debajyoti0606 Sep 10, 2025
74114fb
UI-bug-fixe
avirupsinha12 Sep 10, 2025
9de875a
cors-issue-fixes
debojyoti-git Sep 10, 2025
c002488
bug-fixes
debajyoti0606 Sep 11, 2025
f9585a3
cors-issue-fixes
debojyoti-git Sep 11, 2025
d60fd5e
Refactor Codebase and removed formatting issues and added env default
avirupsinha12 Sep 11, 2025
64707f2
prompt-summariser-tool-integration
debojyoti-git Sep 11, 2025
4286617
add-search-and-icon-fix
debajyoti0606 Sep 11, 2025
462c443
TypeScript Build issues with chatmessage
avirupsinha12 Sep 11, 2025
986f734
added-dynamic-model-selection
debajyoti0606 Sep 11, 2025
5a36be8
Fixed hardcoded keys and refactored
avirupsinha12 Sep 11, 2025
f1e320d
remove hardcoding for api keys of gemini
avirupsinha12 Sep 11, 2025
7191573
Implemented Hono client api calls and removed fetch api calls
avirupsinha12 Sep 12, 2025
9e6a8bc
Removed unnceccesary files and scripts and fixed auth middleware
avirupsinha12 Sep 12, 2025
cc1dddd
removed Auth byepass for workflow routes now handled in xyne middleware
avirupsinha12 Sep 12, 2025
5b16c1e
workflow integration mvp final commit
avirupsinha12 Sep 12, 2025
767233d
Added AuthMiddleware for workflow apis and resolved comments
avirupsinha12 Sep 15, 2025
4fda096
server typescript issues resolved
avirupsinha12 Sep 15, 2025
cae2c0d
ui-bug-fixes
debajyoti0606 Sep 15, 2025
40fe1fa
Fixed build issues tsc server
avirupsinha12 Sep 15, 2025
a6efe6f
Workflow routes apis use jwt auth middleware and hono api loggings
avirupsinha12 Sep 15, 2025
ef915f3
Server comments resolved
avirupsinha12 Sep 15, 2025
fe99246
code-cleanup
debajyoti0606 Sep 15, 2025
57fa5f8
added gentree routes and final commit workflow
avirupsinha12 Sep 15, 2025
906d5e2
agent-ui-fix
debajyoti0606 Sep 15, 2025
77f0051
minor-bug-fixes
debajyoti0606 Sep 15, 2025
cc2c12c
Dark mode fixes and final commit workflow integration
avirupsinha12 Sep 15, 2025
375816a
remove-logs
debajyoti0606 Sep 15, 2025
0221d49
Workflow Integration final commit and refactor
avirupsinha12 Sep 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified frontend/bun.lockb
Binary file not shown.
3 changes: 3 additions & 0 deletions frontend/src/assets/Document.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions frontend/src/assets/android.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion frontend/src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ export const Sidebar = ({
</Tooltip>
</div>

<Link
<Link
to="/workflow"
className={cn(
"flex w-8 h-8 items-center justify-center hover:bg-[#D8DFE680] dark:hover:bg-gray-700 rounded-md mt-[10px]",
Expand Down
320 changes: 320 additions & 0 deletions frontend/src/components/ui/dropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,320 @@
import React, { useState, useRef, useEffect } from "react"
import { ChevronDown, Check } from "lucide-react"
import { cn } from "@/lib/utils"

interface DropdownOption {
value: string
label: string
disabled?: boolean
icon?: React.ReactNode
}

interface DropdownProps {
options: DropdownOption[]
value?: string
placeholder?: string
onSelect: (value: string) => void
disabled?: boolean
className?: string
variant?: "default" | "outline" | "ghost"
size?: "sm" | "md" | "lg"
showCheck?: boolean
searchable?: boolean
loading?: boolean
error?: boolean
maxHeight?: string
position?: "bottom" | "top" | "auto"
width?: string
rounded?: string
border?: string
fontSize?: string
}

const Dropdown: React.FC<DropdownProps> = ({
options,
value,
placeholder = "Select an option",
onSelect,
disabled = false,
className,
variant = "default",
size = "md",
showCheck = true,
searchable = false,
loading = false,
error = false,
maxHeight = "200px",
position = "auto",
width,
rounded,
border,
fontSize,
}) => {
const [isOpen, setIsOpen] = useState(false)
const [searchTerm, setSearchTerm] = useState("")
const [dropdownPosition, setDropdownPosition] = useState<"bottom" | "top">("bottom")
const dropdownRef = useRef<HTMLDivElement>(null)
const triggerRef = useRef<HTMLButtonElement>(null)
const searchInputRef = useRef<HTMLInputElement>(null)

// Filter options based on search term
const filteredOptions = searchable
? options.filter(option =>
option.label.toLowerCase().includes(searchTerm.toLowerCase())
)
: options

// Find selected option
const selectedOption = options.find(option => option.value === value)

// Handle position calculation
useEffect(() => {
if (isOpen && position === "auto" && triggerRef.current) {
const rect = triggerRef.current.getBoundingClientRect()
const viewportHeight = window.innerHeight
const spaceBelow = viewportHeight - rect.bottom
const spaceAbove = rect.top

// If there's more space above than below and not enough space below for dropdown
if (spaceAbove > spaceBelow && spaceBelow < 200) {
setDropdownPosition("top")
} else {
setDropdownPosition("bottom")
}
} else if (position !== "auto") {
setDropdownPosition(position)
}
}, [isOpen, position])

// Close dropdown when clicking outside
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
setIsOpen(false)
setSearchTerm("")
}
}

if (isOpen) {
document.addEventListener("mousedown", handleClickOutside)
// Focus search input if searchable
if (searchable && searchInputRef.current) {
setTimeout(() => searchInputRef.current?.focus(), 100)
}
}

return () => {
document.removeEventListener("mousedown", handleClickOutside)
}
}, [isOpen, searchable])

// Handle keyboard navigation
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (!isOpen) return

if (event.key === "Escape") {
setIsOpen(false)
setSearchTerm("")
triggerRef.current?.focus()
}
}

document.addEventListener("keydown", handleKeyDown)
return () => document.removeEventListener("keydown", handleKeyDown)
}, [isOpen])

const handleSelect = (optionValue: string) => {
if (disabled) return

onSelect(optionValue)
setIsOpen(false)
setSearchTerm("")
triggerRef.current?.focus()
}

const handleToggle = () => {
if (disabled) return
setIsOpen(!isOpen)
if (isOpen) {
setSearchTerm("")
}
}

// Variant styles - Updated to use lighter gray colors
const getVariantStyles = () => {
if (border) {
// Use external border prop
switch (variant) {
case "outline":
return `bg-white dark:bg-gray-900 hover:border-gray-300 dark:hover:border-gray-500 text-gray-900 dark:text-gray-100`
case "ghost":
return "border-none bg-transparent hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-900 dark:text-gray-100"
default:
return `bg-gray-50 dark:bg-gray-800 hover:border-gray-300 dark:hover:border-gray-500 text-gray-900 dark:text-gray-100`
}
}

// Default lighter border colors
switch (variant) {
case "outline":
return "border border-gray-200 dark:border-gray-600 bg-white dark:bg-gray-900 hover:border-gray-300 dark:hover:border-gray-500 text-gray-900 dark:text-gray-100"
case "ghost":
return "border-none bg-transparent hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-900 dark:text-gray-100"
default:
return "border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 hover:border-gray-300 dark:hover:border-gray-500 text-gray-900 dark:text-gray-100"
}
}

// Size styles - Updated to use external fontSize when provided
const getSizeStyles = () => {
const textSize = fontSize || "text-sm"
switch (size) {
case "sm":
return `h-8 px-2 ${textSize}`
case "lg":
return `h-12 px-4 ${textSize}`
default:
return `h-10 px-3 ${textSize}`
}
}

const triggerClassName = cn(
"relative w-full flex items-center justify-between transition-colors focus:outline-none",
rounded ? "" : "rounded-lg",
getSizeStyles(),
getVariantStyles(),
{
"cursor-not-allowed opacity-50": disabled,
"border-red-500 dark:border-red-400": error,
},
className
)

const dropdownClassName = cn(
"absolute z-50 mt-1 bg-white dark:bg-gray-900 shadow-lg overflow-hidden w-full",
border ? "" : "border border-gray-200 dark:border-gray-600",
rounded ? "" : "rounded-lg",
{
"bottom-full mb-1 mt-0": dropdownPosition === "top",
}
)

return (
<div
className="relative"
ref={dropdownRef}
style={{
...(width ? { width } : {}),
...(rounded ? { borderRadius: rounded } : {})
}}
>
<button
ref={triggerRef}
type="button"
onClick={handleToggle}
className={triggerClassName}
style={{
...(rounded ? { borderRadius: rounded } : {}),
...(border ? { border: isOpen ? "1px solid #000000" : border } : {}),
...(isOpen && !border ? { border: "1px solid #000000" } : {})
}}
disabled={disabled}
aria-haspopup="listbox"
aria-expanded={isOpen}
>
<div className="flex items-center gap-2 flex-1 text-left">
{selectedOption?.icon && (
<span className="flex-shrink-0">{selectedOption.icon}</span>
)}
<span className={cn(
"truncate",
!selectedOption && "text-gray-500 dark:text-gray-400",
selectedOption && "text-gray-900 dark:text-gray-100"
)}>
{selectedOption?.label || placeholder}
</span>
</div>

<div className="flex items-center gap-2">
{loading && (
<div className="w-4 h-4 border-2 border-gray-300 border-t-gray-600 dark:border-t-gray-400 rounded-full animate-spin" />
)}
<ChevronDown
className={cn(
"w-4 h-4 text-gray-400 transition-transform",
isOpen && "rotate-180"
)}
/>
</div>
</button>

{isOpen && (
<div
className={dropdownClassName}
style={{
...(rounded ? { borderRadius: rounded } : {}),
...(border ? { border: border } : {})
}}
>
{searchable && (
<div className="p-2 border-b border-gray-200 dark:border-gray-600">
<input
ref={searchInputRef}
type="text"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder="Search options..."
className={cn(
"w-full px-2 py-1 border rounded bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 placeholder-gray-500 dark:placeholder-gray-400 focus:outline-none focus:ring-1 focus:ring-gray-400 dark:focus:ring-gray-500",
border ? "" : "border-gray-200 dark:border-gray-600",
fontSize || "text-sm"
)}
style={border ? { border: border } : {}}
/>
</div>
)}

<div
className="overflow-y-auto"
style={{ maxHeight }}
>
{filteredOptions.length === 0 ? (
<div className="px-3 py-2 text-sm text-gray-500 dark:text-gray-400">
{searchable && searchTerm ? "No options found" : "No options available"}
</div>
) : (
filteredOptions.map((option) => (
<button
key={option.value}
type="button"
onClick={() => handleSelect(option.value)}
disabled={option.disabled}
className={cn(
"w-full flex items-center gap-2 px-3 py-2 text-left hover:bg-gray-100 dark:hover:bg-gray-700 focus:bg-gray-100 dark:focus:bg-gray-700 focus:outline-none text-gray-900 dark:text-gray-100",
fontSize || "text-sm",
{
"bg-gray-100 dark:bg-gray-700 text-gray-900 dark:text-gray-100 font-medium": option.value === value,
"cursor-not-allowed opacity-50": option.disabled,
}
)}
>
{option.icon && (
<span className="flex-shrink-0">{option.icon}</span>
)}
<span className="flex-1 truncate">{option.label}</span>
{showCheck && option.value === value && (
<Check className="w-4 h-4 text-gray-700 dark:text-gray-300" />
)}
</button>
))
)}
</div>
</div>
)}
</div>
)
}

export default Dropdown
export type { DropdownOption, DropdownProps }
Loading