Files
vexplor/frontend/lib/registry/pop-components/pop-shared/ColumnCombobox.tsx
SeongHyun Kim e3ae8d273c feat(pop): 컴포넌트 연결 단순화 + 상태 변경 규칙 UI 개선 + 조회 키 설정
컴포넌트 연결 단순화
- ConnectionEditor: 이벤트 연결 시 "어디로" Select 1개로 단순화
- useConnectionResolver: 호환 이벤트 자동 라우팅 (_auto 모드)
- connectionMeta에 category(event/filter/data) 필드 추가

상태 변경 규칙 UI 개선
- StatusChangeRule 타입 통합, 모든 버튼 프리셋에서 사용 가능
- TableCombobox/ColumnCombobox 공용 컴포넌트 추출 (pop-shared/)
- 테이블/컬럼 드롭다운, 고정값/조건부 값 설정 UI
- 입고확정 API 신규 (popActionRoutes.ts, 동적 상태 변경 처리)

조회 키 자동/수동 설정
- 대상 테이블 기반 자동 판단 (cart_items -> id, 그 외 -> row_key -> PK)
- 수동 모드: 카드 항목 필드와 대상 PK 컬럼을 직접 지정 가능
- PK 컬럼명 동적 표시 (isPrimaryKey 정보 활용)
2026-03-03 15:31:13 +09:00

106 lines
3.0 KiB
TypeScript

"use client";
import React, { useState, useMemo } from "react";
import { Check, ChevronsUpDown } from "lucide-react";
import { Button } from "@/components/ui/button";
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "@/components/ui/command";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { cn } from "@/lib/utils";
import type { ColumnInfo } from "../pop-dashboard/utils/dataFetcher";
interface ColumnComboboxProps {
columns: ColumnInfo[];
value: string;
onSelect: (columnName: string) => void;
placeholder?: string;
}
export function ColumnCombobox({
columns,
value,
onSelect,
placeholder = "컬럼을 선택하세요",
}: ColumnComboboxProps) {
const [open, setOpen] = useState(false);
const [search, setSearch] = useState("");
const filtered = useMemo(() => {
if (!search) return columns;
const q = search.toLowerCase();
return columns.filter((c) => c.name.toLowerCase().includes(q));
}, [columns, search]);
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
role="combobox"
aria-expanded={open}
className="mt-1 h-8 w-full justify-between text-xs"
>
{value || placeholder}
<ChevronsUpDown className="ml-2 h-3.5 w-3.5 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent
className="p-0"
style={{ width: "var(--radix-popover-trigger-width)" }}
align="start"
>
<Command shouldFilter={false}>
<CommandInput
placeholder="컬럼명 검색..."
className="text-xs"
value={search}
onValueChange={setSearch}
/>
<CommandList>
<CommandEmpty className="py-4 text-center text-xs">
.
</CommandEmpty>
<CommandGroup>
{filtered.map((col) => (
<CommandItem
key={col.name}
value={col.name}
onSelect={() => {
onSelect(col.name);
setOpen(false);
setSearch("");
}}
className="text-xs"
>
<Check
className={cn(
"mr-2 h-3.5 w-3.5",
value === col.name ? "opacity-100" : "opacity-0"
)}
/>
<div className="flex items-center gap-2">
<span>{col.name}</span>
<span className="text-[10px] text-muted-foreground">
{col.type}
</span>
</div>
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
);
}