refactor: pop-search 레거시 정리 + 하위 테이블 자동 판단 + 초기값 프로필 세팅
MES 고정 구조에 맞게 검색/연결/필터 컴포넌트를 간소화하고,
하위 테이블 필터를 수동 설정에서 자동 판단으로 전환한다.
[pop-search 레거시 정리]
- LegacySearchInputType, StatusChipConfig, StatusChipStyle,
SelectDataSource 등 미사용 타입 제거
- status-chip, multi-select, combo 입력 타입 제거
(DB 호환: normalizeInputType에서 text로 정규화)
- 설정 패널에서 status-chip 관련 UI/안내문 제거
- SEARCH_INPUT_TYPE_LABELS 간소화 (7종 -> 5종)
[하위 테이블 자동 판단]
- PopCardListV2Component: subTableKeys useMemo 추가
(processFlow rawData 키셋에서 하위 테이블 컬럼 자동 추출)
- isSubTableColumn useCallback: filterConfig.isSubTable 하위 호환 +
subTableKeys 기반 자동 판단으로 메인/하위 필터 분류
- ConnectionEditor: "하위 테이블 기준으로 필터" 체크박스 UI 제거,
isSubTable 상태 및 setIsSubTable 전부 제거
- 컬럼 선택 드롭다운: 메인+하위 테이블 컬럼 통합 표시
- 기존 연결 배지 "하위 테이블" -> "자동 판단"으로 변경
[초기값 프로필 세팅]
- PopSearchConfig.initialValueSource 타입 추가
({ type: "user_profile", column: string })
- PopSearchComponent: useAuth + useEffect로 사용자 프로필 값
자동 필터 발행 (userId, deptCode, positionCode 등)
- 설정 패널: "초기값 자동 세팅" Select 드롭다운 추가
(사용 안 함 / 사용자ID / 부서코드 / 직급 등 7개 옵션)
This commit is contained in:
parent
d001f82565
commit
1d85de8bf6
|
|
@ -181,5 +181,6 @@ scripts/browser-test-*.js
|
|||
|
||||
# 개인 작업 문서
|
||||
popdocs/
|
||||
kshdocs/
|
||||
.cursor/rules/popdocs-safety.mdc
|
||||
.cursor/rules/overtime-registration.mdc
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ import React from "react";
|
|||
import { ArrowRight, Link2, Unlink2, Plus, Trash2, Pencil, X, Loader2 } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
|
|
@ -172,7 +171,7 @@ function SendSection({
|
|||
</span>
|
||||
{conn.filterConfig.isSubTable && (
|
||||
<span className="rounded bg-amber-100 px-1.5 py-0.5 text-[9px] text-amber-700">
|
||||
하위 테이블
|
||||
자동 판단
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -229,9 +228,6 @@ function SimpleConnectionForm({
|
|||
const [selectedTargetId, setSelectedTargetId] = React.useState(
|
||||
initial?.targetComponent || ""
|
||||
);
|
||||
const [isSubTable, setIsSubTable] = React.useState(
|
||||
initial?.filterConfig?.isSubTable || false
|
||||
);
|
||||
const [targetColumn, setTargetColumn] = React.useState(
|
||||
initial?.filterConfig?.targetColumn || ""
|
||||
);
|
||||
|
|
@ -255,23 +251,34 @@ function SimpleConnectionForm({
|
|||
&& targetReg?.connectionMeta?.receivable?.some((r) => r.type === "filter_value");
|
||||
|
||||
const subTableName = targetComp ? extractSubTableName(targetComp) : null;
|
||||
const mainTableName = (() => {
|
||||
const cfg = targetComp?.config as Record<string, unknown> | undefined;
|
||||
const ds = cfg?.dataSource as { tableName?: string } | undefined;
|
||||
return ds?.tableName || null;
|
||||
})();
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!isSubTable || !subTableName) {
|
||||
if (!isFilterConnection || !selectedTargetId) {
|
||||
setSubColumns([]);
|
||||
return;
|
||||
}
|
||||
const tables = [mainTableName, subTableName].filter(Boolean) as string[];
|
||||
if (tables.length === 0) { setSubColumns([]); return; }
|
||||
setLoadingColumns(true);
|
||||
getTableColumns(subTableName)
|
||||
.then((res) => {
|
||||
const cols = res.success && res.data?.columns;
|
||||
if (Array.isArray(cols)) {
|
||||
setSubColumns(cols.map((c) => c.columnName || "").filter(Boolean));
|
||||
Promise.all(tables.map((t) => getTableColumns(t)))
|
||||
.then((results) => {
|
||||
const allCols = new Set<string>();
|
||||
for (const res of results) {
|
||||
const cols = res.success && res.data?.columns;
|
||||
if (Array.isArray(cols)) {
|
||||
cols.forEach((c) => { if (c.columnName) allCols.add(c.columnName); });
|
||||
}
|
||||
}
|
||||
setSubColumns([...allCols].sort());
|
||||
})
|
||||
.catch(() => setSubColumns([]))
|
||||
.finally(() => setLoadingColumns(false));
|
||||
}, [isSubTable, subTableName]);
|
||||
}, [isFilterConnection, selectedTargetId, mainTableName, subTableName]);
|
||||
|
||||
const handleSubmit = () => {
|
||||
if (!selectedTargetId) return;
|
||||
|
|
@ -290,11 +297,10 @@ function SimpleConnectionForm({
|
|||
label: `${srcLabel} → ${tgtLabel}`,
|
||||
};
|
||||
|
||||
if (isFilterConnection && isSubTable && targetColumn) {
|
||||
if (isFilterConnection && targetColumn) {
|
||||
conn.filterConfig = {
|
||||
targetColumn,
|
||||
filterMode: filterMode as "equals" | "contains" | "starts_with" | "range",
|
||||
isSubTable: true,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -302,7 +308,6 @@ function SimpleConnectionForm({
|
|||
|
||||
if (!initial) {
|
||||
setSelectedTargetId("");
|
||||
setIsSubTable(false);
|
||||
setTargetColumn("");
|
||||
setFilterMode("equals");
|
||||
}
|
||||
|
|
@ -328,7 +333,6 @@ function SimpleConnectionForm({
|
|||
value={selectedTargetId}
|
||||
onValueChange={(v) => {
|
||||
setSelectedTargetId(v);
|
||||
setIsSubTable(false);
|
||||
setTargetColumn("");
|
||||
}}
|
||||
>
|
||||
|
|
@ -345,62 +349,47 @@ function SimpleConnectionForm({
|
|||
</Select>
|
||||
</div>
|
||||
|
||||
{isFilterConnection && selectedTargetId && subTableName && (
|
||||
{isFilterConnection && selectedTargetId && (
|
||||
<div className="space-y-2 rounded bg-muted/50 p-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
id={`isSubTable_${component.id}`}
|
||||
checked={isSubTable}
|
||||
onCheckedChange={(v) => {
|
||||
setIsSubTable(v === true);
|
||||
if (!v) setTargetColumn("");
|
||||
}}
|
||||
/>
|
||||
<label htmlFor={`isSubTable_${component.id}`} className="text-[10px] text-muted-foreground cursor-pointer">
|
||||
하위 테이블 기준으로 필터 ({subTableName})
|
||||
</label>
|
||||
<div className="space-y-1">
|
||||
<span className="text-[10px] text-muted-foreground">대상 컬럼</span>
|
||||
{loadingColumns ? (
|
||||
<div className="flex items-center gap-1 py-1">
|
||||
<Loader2 className="h-3 w-3 animate-spin text-muted-foreground" />
|
||||
<span className="text-[10px] text-muted-foreground">컬럼 로딩 중...</span>
|
||||
</div>
|
||||
) : (
|
||||
<Select value={targetColumn} onValueChange={setTargetColumn}>
|
||||
<SelectTrigger className="h-7 text-xs">
|
||||
<SelectValue placeholder="컬럼 선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{subColumns.filter(Boolean).map((col) => (
|
||||
<SelectItem key={col} value={col} className="text-xs">
|
||||
{col}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{isSubTable && (
|
||||
<div className="space-y-2 pl-5">
|
||||
<div className="space-y-1">
|
||||
<span className="text-[10px] text-muted-foreground">대상 컬럼</span>
|
||||
{loadingColumns ? (
|
||||
<div className="flex items-center gap-1 py-1">
|
||||
<Loader2 className="h-3 w-3 animate-spin text-muted-foreground" />
|
||||
<span className="text-[10px] text-muted-foreground">컬럼 로딩 중...</span>
|
||||
</div>
|
||||
) : (
|
||||
<Select value={targetColumn} onValueChange={setTargetColumn}>
|
||||
<SelectTrigger className="h-7 text-xs">
|
||||
<SelectValue placeholder="컬럼 선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{subColumns.filter(Boolean).map((col) => (
|
||||
<SelectItem key={col} value={col} className="text-xs">
|
||||
{col}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
<span className="text-[10px] text-muted-foreground">비교 방식</span>
|
||||
<Select value={filterMode} onValueChange={setFilterMode}>
|
||||
<SelectTrigger className="h-7 text-xs">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="equals" className="text-xs">일치 (equals)</SelectItem>
|
||||
<SelectItem value="contains" className="text-xs">포함 (contains)</SelectItem>
|
||||
<SelectItem value="starts_with" className="text-xs">시작 (starts_with)</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="space-y-1">
|
||||
<span className="text-[10px] text-muted-foreground">비교 방식</span>
|
||||
<Select value={filterMode} onValueChange={setFilterMode}>
|
||||
<SelectTrigger className="h-7 text-xs">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="equals" className="text-xs">일치 (equals)</SelectItem>
|
||||
<SelectItem value="contains" className="text-xs">포함 (contains)</SelectItem>
|
||||
<SelectItem value="starts_with" className="text-xs">시작 (starts_with)</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<p className="text-[9px] text-muted-foreground">
|
||||
메인/하위 테이블 구분은 자동으로 판단됩니다
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
|
|||
|
|
@ -569,23 +569,39 @@ export function PopCardListV2Component({
|
|||
);
|
||||
}, [timelineSource]);
|
||||
|
||||
// 외부 필터 (메인 테이블 + 하위 테이블 분기)
|
||||
// processFlow rawData 키셋 (하위 테이블 컬럼 자동 판단용)
|
||||
const subTableKeys = useMemo(() => {
|
||||
for (const row of rows) {
|
||||
const pf = row.__processFlow__ as TimelineProcessStep[] | undefined;
|
||||
if (pf?.[0]?.rawData) return new Set(Object.keys(pf[0].rawData));
|
||||
}
|
||||
return new Set<string>();
|
||||
}, [rows]);
|
||||
|
||||
// 필터 컬럼이 하위 테이블에 속하는지 자동 판단
|
||||
const isSubTableColumn = useCallback((filter: { fieldName: string; filterConfig?: { targetColumn: string; isSubTable?: boolean } }) => {
|
||||
if (filter.filterConfig?.isSubTable) return true;
|
||||
const col = filter.filterConfig?.targetColumn || filter.fieldName;
|
||||
return col ? subTableKeys.has(col) : false;
|
||||
}, [subTableKeys]);
|
||||
|
||||
// 외부 필터 (자동 분류: 컬럼이 processFlow에 있으면 subFilter)
|
||||
const filteredRows = useMemo(() => {
|
||||
if (externalFilters.size === 0) return duplicateAcceptableCards(rows);
|
||||
|
||||
const allFilters = [...externalFilters.values()];
|
||||
const mainFilters = allFilters.filter((f) => !f.filterConfig?.isSubTable);
|
||||
const subFilters = allFilters.filter((f) => f.filterConfig?.isSubTable);
|
||||
const mainFilters = allFilters.filter((f) => !isSubTableColumn(f));
|
||||
const subFilters = allFilters.filter((f) => isSubTableColumn(f));
|
||||
|
||||
const afterDuplicate = applySubFilterAndDuplicate(rows, subFilters);
|
||||
return applyMainFilters(afterDuplicate, mainFilters, subFilters.length > 0);
|
||||
}, [rows, externalFilters, duplicateAcceptableCards, applySubFilterAndDuplicate, applyMainFilters]);
|
||||
}, [rows, externalFilters, duplicateAcceptableCards, applySubFilterAndDuplicate, applyMainFilters, isSubTableColumn]);
|
||||
|
||||
// 하위 필터 활성 여부
|
||||
const hasActiveSubFilter = useMemo(() => {
|
||||
if (externalFilters.size === 0) return false;
|
||||
return [...externalFilters.values()].some((f) => f.filterConfig?.isSubTable);
|
||||
}, [externalFilters]);
|
||||
return [...externalFilters.values()].some((f) => isSubTableColumn(f));
|
||||
}, [externalFilters, isSubTableColumn]);
|
||||
|
||||
// 선택 모드 일괄 처리
|
||||
const handleSelectModeAction = useCallback(async (btnConfig: SelectModeButtonConfig) => {
|
||||
|
|
@ -675,12 +691,12 @@ export function PopCardListV2Component({
|
|||
if (nonStatusFilters.size === 0) return duplicateAcceptableCards(rows);
|
||||
|
||||
const allFilters = [...nonStatusFilters.values()];
|
||||
const mainFilters = allFilters.filter((f) => !f.filterConfig?.isSubTable);
|
||||
const subFilters = allFilters.filter((f) => f.filterConfig?.isSubTable);
|
||||
const mainFilters = allFilters.filter((f) => !isSubTableColumn(f));
|
||||
const subFilters = allFilters.filter((f) => isSubTableColumn(f));
|
||||
|
||||
const afterDuplicate = applySubFilterAndDuplicate(rows, subFilters);
|
||||
return applyMainFilters(afterDuplicate, mainFilters, subFilters.length > 0);
|
||||
}, [rows, filteredRows, externalFilters, duplicateAcceptableCards, applySubFilterAndDuplicate, applyMainFilters]);
|
||||
}, [rows, filteredRows, externalFilters, duplicateAcceptableCards, applySubFilterAndDuplicate, applyMainFilters, isSubTableColumn]);
|
||||
|
||||
// 카운트 집계용 rows 발행 (status-bar 필터 제외)
|
||||
// originalCount: 복제 카드를 제외한 원본 카드 수
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import {
|
|||
import { format, startOfWeek, endOfWeek, startOfMonth, endOfMonth } from "date-fns";
|
||||
import { ko } from "date-fns/locale";
|
||||
import { usePopEvent } from "@/hooks/pop";
|
||||
import { useAuth } from "@/hooks/useAuth";
|
||||
import { dataApi } from "@/lib/api/data";
|
||||
import type {
|
||||
PopSearchConfig,
|
||||
|
|
@ -67,9 +68,11 @@ export function PopSearchComponent({
|
|||
}: PopSearchComponentProps) {
|
||||
const config = { ...DEFAULT_CONFIG, ...(rawConfig || {}) };
|
||||
const { publish, subscribe, setSharedData } = usePopEvent(screenId || "");
|
||||
const { user } = useAuth();
|
||||
const [value, setValue] = useState<unknown>(config.defaultValue ?? "");
|
||||
const [modalDisplayText, setModalDisplayText] = useState("");
|
||||
const [simpleModalOpen, setSimpleModalOpen] = useState(false);
|
||||
const initialValueAppliedRef = useRef(false);
|
||||
|
||||
const normalizedType = normalizeInputType(config.inputType as string);
|
||||
const isModalType = normalizedType === "modal";
|
||||
|
|
@ -107,6 +110,21 @@ export function PopSearchComponent({
|
|||
[fieldKey, publish, setSharedData, componentId, resolveFilterMode, config.filterColumns]
|
||||
);
|
||||
|
||||
// 초기값 고정 세팅: 사용자 프로필에서 자동으로 값 설정
|
||||
useEffect(() => {
|
||||
if (initialValueAppliedRef.current) return;
|
||||
if (!config.initialValueSource || config.initialValueSource.type !== "user_profile") return;
|
||||
if (!user) return;
|
||||
|
||||
const col = config.initialValueSource.column;
|
||||
const profileValue = (user as Record<string, unknown>)[col];
|
||||
if (profileValue != null && profileValue !== "") {
|
||||
initialValueAppliedRef.current = true;
|
||||
const timer = setTimeout(() => emitFilterChanged(profileValue), 100);
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
}, [user, config.initialValueSource, emitFilterChanged]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!componentId) return;
|
||||
const unsub = subscribe(
|
||||
|
|
@ -238,12 +256,6 @@ function SearchInputRenderer({ config, value, onChange, modalDisplayText, onModa
|
|||
return <ToggleSearchInput value={Boolean(value)} onChange={onChange} />;
|
||||
case "modal":
|
||||
return <ModalSearchInput config={config} displayText={modalDisplayText || ""} onClick={onModalOpen} onClear={onModalClear} />;
|
||||
case "status-chip":
|
||||
return (
|
||||
<div className="flex h-full items-center px-2 text-[10px] text-muted-foreground">
|
||||
pop-status-bar 컴포넌트를 사용하세요
|
||||
</div>
|
||||
);
|
||||
default:
|
||||
return <PlaceholderInput inputType={config.inputType} />;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -209,6 +209,39 @@ function StepBasicSettings({ cfg, update }: StepProps) {
|
|||
</div>
|
||||
)}
|
||||
|
||||
{/* 초기값 고정 세팅 */}
|
||||
<div className="space-y-1">
|
||||
<Label className="text-[10px]">초기값 자동 세팅</Label>
|
||||
<Select
|
||||
value={cfg.initialValueSource?.column || "__none__"}
|
||||
onValueChange={(v) => {
|
||||
if (v === "__none__") {
|
||||
update({ initialValueSource: undefined });
|
||||
} else {
|
||||
update({ initialValueSource: { type: "user_profile", column: v } });
|
||||
}
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="h-8 text-xs">
|
||||
<SelectValue placeholder="사용 안 함" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="__none__" className="text-xs">사용 안 함</SelectItem>
|
||||
<SelectItem value="userId" className="text-xs">사용자 ID</SelectItem>
|
||||
<SelectItem value="userName" className="text-xs">사용자 이름</SelectItem>
|
||||
<SelectItem value="deptCode" className="text-xs">부서 코드</SelectItem>
|
||||
<SelectItem value="deptName" className="text-xs">부서명</SelectItem>
|
||||
<SelectItem value="positionCode" className="text-xs">직급 코드</SelectItem>
|
||||
<SelectItem value="positionName" className="text-xs">직급명</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{cfg.initialValueSource && (
|
||||
<p className="text-[9px] text-muted-foreground">
|
||||
화면 진입 시 로그인 사용자의 {cfg.initialValueSource.column} 값으로 자동 필터링됩니다
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -231,15 +264,6 @@ function StepDetailSettings({ cfg, update, allComponents, connections, component
|
|||
return <DatePresetDetailSettings cfg={cfg} update={update} allComponents={allComponents} connections={connections} componentId={componentId} />;
|
||||
case "modal":
|
||||
return <ModalDetailSettings cfg={cfg} update={update} />;
|
||||
case "status-chip":
|
||||
return (
|
||||
<div className="rounded-lg bg-muted/50 p-3">
|
||||
<p className="text-[10px] text-muted-foreground">
|
||||
상태 칩은 pop-status-bar 컴포넌트로 분리되었습니다.
|
||||
새로운 "상태 바" 컴포넌트를 사용해주세요.
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
case "toggle":
|
||||
return (
|
||||
<div className="rounded-lg bg-muted/50 p-3">
|
||||
|
|
|
|||
|
|
@ -1,25 +1,20 @@
|
|||
// ===== pop-search 전용 타입 =====
|
||||
// 단일 필드 검색 컴포넌트. 그리드 한 칸 = 검색 필드 하나.
|
||||
|
||||
/** 검색 필드 입력 타입 (10종) */
|
||||
/** 검색 필드 입력 타입 */
|
||||
export type SearchInputType =
|
||||
| "text"
|
||||
| "number"
|
||||
| "date"
|
||||
| "date-preset"
|
||||
| "select"
|
||||
| "multi-select"
|
||||
| "combo"
|
||||
| "modal"
|
||||
| "toggle"
|
||||
| "status-chip";
|
||||
| "toggle";
|
||||
|
||||
/** 레거시 입력 타입 (DB에 저장된 기존 값 호환용) */
|
||||
export type LegacySearchInputType = "modal-table" | "modal-card" | "modal-icon-grid";
|
||||
|
||||
/** 레거시 타입 -> modal로 정규화 */
|
||||
/** 레거시 입력 타입 정규화 (DB 호환) */
|
||||
export function normalizeInputType(t: string): SearchInputType {
|
||||
if (t === "modal-table" || t === "modal-card" || t === "modal-icon-grid") return "modal";
|
||||
if (t === "status-chip" || t === "multi-select" || t === "combo") return "text";
|
||||
return t as SearchInputType;
|
||||
}
|
||||
|
||||
|
|
@ -38,15 +33,6 @@ export interface SelectOption {
|
|||
label: string;
|
||||
}
|
||||
|
||||
/** 셀렉트 옵션 데이터 소스 (DB에서 동적 로딩) */
|
||||
export interface SelectDataSource {
|
||||
tableName: string;
|
||||
valueColumn: string;
|
||||
labelColumn: string;
|
||||
sortColumn?: string;
|
||||
sortDirection?: "asc" | "desc";
|
||||
}
|
||||
|
||||
/** 모달 보여주기 방식: 테이블 or 아이콘 */
|
||||
export type ModalDisplayStyle = "table" | "icon";
|
||||
|
||||
|
|
@ -79,22 +65,9 @@ export interface ModalSelectConfig {
|
|||
distinct?: boolean;
|
||||
}
|
||||
|
||||
/** @deprecated status-chip은 pop-status-bar로 분리됨. 레거시 호환용. */
|
||||
export type StatusChipStyle = "tab" | "pill";
|
||||
|
||||
/** @deprecated status-chip은 pop-status-bar로 분리됨. 레거시 호환용. */
|
||||
export interface StatusChipConfig {
|
||||
showCount?: boolean;
|
||||
countColumn?: string;
|
||||
allowAll?: boolean;
|
||||
allLabel?: string;
|
||||
chipStyle?: StatusChipStyle;
|
||||
useSubCount?: boolean;
|
||||
}
|
||||
|
||||
/** pop-search 전체 설정 */
|
||||
export interface PopSearchConfig {
|
||||
inputType: SearchInputType | LegacySearchInputType;
|
||||
inputType: SearchInputType | string;
|
||||
fieldName: string;
|
||||
placeholder?: string;
|
||||
defaultValue?: unknown;
|
||||
|
|
@ -103,9 +76,8 @@ export interface PopSearchConfig {
|
|||
debounceMs?: number;
|
||||
triggerOnEnter?: boolean;
|
||||
|
||||
// select/multi-select 전용
|
||||
// select 전용
|
||||
options?: SelectOption[];
|
||||
optionsDataSource?: SelectDataSource;
|
||||
|
||||
// date 전용
|
||||
dateSelectionMode?: DateSelectionMode;
|
||||
|
|
@ -117,9 +89,6 @@ export interface PopSearchConfig {
|
|||
// modal 전용
|
||||
modalConfig?: ModalSelectConfig;
|
||||
|
||||
// status-chip 전용
|
||||
statusChipConfig?: StatusChipConfig;
|
||||
|
||||
// 라벨
|
||||
labelText?: string;
|
||||
labelVisible?: boolean;
|
||||
|
|
@ -129,6 +98,12 @@ export interface PopSearchConfig {
|
|||
|
||||
// 필터 대상 컬럼 복수 선택 (fieldName은 대표 컬럼, filterColumns는 전체 대상)
|
||||
filterColumns?: string[];
|
||||
|
||||
// 초기값 고정 세팅 (사용자 프로필에서 자동으로 값 설정)
|
||||
initialValueSource?: {
|
||||
type: "user_profile";
|
||||
column: string;
|
||||
};
|
||||
}
|
||||
|
||||
/** 기본 설정값 (레지스트리 + 컴포넌트 공유) */
|
||||
|
|
@ -157,17 +132,8 @@ export const SEARCH_INPUT_TYPE_LABELS: Record<SearchInputType, string> = {
|
|||
date: "날짜",
|
||||
"date-preset": "날짜 프리셋",
|
||||
select: "단일 선택",
|
||||
"multi-select": "다중 선택",
|
||||
combo: "자동완성",
|
||||
modal: "모달",
|
||||
toggle: "토글",
|
||||
"status-chip": "상태 칩 (대시보드)",
|
||||
};
|
||||
|
||||
/** 상태 칩 스타일 라벨 (설정 패널용) */
|
||||
export const STATUS_CHIP_STYLE_LABELS: Record<StatusChipStyle, string> = {
|
||||
tab: "탭 (큰 숫자)",
|
||||
pill: "알약 (작은 뱃지)",
|
||||
};
|
||||
|
||||
/** 모달 보여주기 방식 라벨 */
|
||||
|
|
|
|||
Loading…
Reference in New Issue