패널 정리중
This commit is contained in:
parent
743ae6dbf1
commit
eeae338cd4
|
|
@ -61,6 +61,24 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
const [displayColumnOpen, setDisplayColumnOpen] = useState(false);
|
||||
const [displayColumnSearch, setDisplayColumnSearch] = useState("");
|
||||
|
||||
// 🎯 플로우 위젯이 화면에 있는지 확인
|
||||
const hasFlowWidget = useMemo(() => {
|
||||
const found = allComponents.some((comp: any) => {
|
||||
// ScreenDesigner에서 저장하는 componentType 속성 확인!
|
||||
const compType = comp.componentType || comp.widgetType || "";
|
||||
|
||||
// "flow-widget" 체크
|
||||
const isFlow = compType === "flow-widget" || compType?.toLowerCase().includes("flow");
|
||||
|
||||
if (isFlow) {
|
||||
console.log("✅ 플로우 위젯 발견!", { id: comp.id, componentType: comp.componentType });
|
||||
}
|
||||
return isFlow;
|
||||
});
|
||||
console.log("🎯 플로우 위젯 존재 여부:", found);
|
||||
return found;
|
||||
}, [allComponents]);
|
||||
|
||||
// 컴포넌트 prop 변경 시 로컬 상태 동기화 (Input만)
|
||||
useEffect(() => {
|
||||
const latestConfig = component.componentConfig || {};
|
||||
|
|
@ -298,7 +316,8 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={modalScreenOpen}
|
||||
className="h-6 w-full px-2 py-0 justify-between" style={{ fontSize: "12px" }}
|
||||
className="h-6 w-full justify-between px-2 py-0"
|
||||
style={{ fontSize: "12px" }}
|
||||
disabled={screensLoading}
|
||||
>
|
||||
{config.action?.targetScreenId
|
||||
|
|
@ -372,7 +391,8 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={modalScreenOpen}
|
||||
className="h-6 w-full px-2 py-0 justify-between" style={{ fontSize: "12px" }}
|
||||
className="h-6 w-full justify-between px-2 py-0"
|
||||
style={{ fontSize: "12px" }}
|
||||
disabled={screensLoading}
|
||||
>
|
||||
{config.action?.targetScreenId
|
||||
|
|
@ -526,7 +546,8 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={displayColumnOpen}
|
||||
className="mt-2 h-8 w-full justify-between text-xs" style={{ fontSize: "12px" }}
|
||||
className="mt-2 h-8 w-full justify-between text-xs"
|
||||
style={{ fontSize: "12px" }}
|
||||
disabled={columnsLoading || tableColumns.length === 0}
|
||||
>
|
||||
{columnsLoading
|
||||
|
|
@ -543,7 +564,9 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
<Command>
|
||||
<CommandInput placeholder="컬럼 검색..." className="text-xs" style={{ fontSize: "12px" }} />
|
||||
<CommandList>
|
||||
<CommandEmpty className="text-xs" style={{ fontSize: "12px" }}>컬럼을 찾을 수 없습니다.</CommandEmpty>
|
||||
<CommandEmpty className="text-xs" style={{ fontSize: "12px" }}>
|
||||
컬럼을 찾을 수 없습니다.
|
||||
</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{tableColumns.map((column) => (
|
||||
<CommandItem
|
||||
|
|
@ -553,7 +576,8 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
onUpdateProperty("componentConfig.action.historyDisplayColumn", currentValue);
|
||||
setDisplayColumnOpen(false);
|
||||
}}
|
||||
className="text-xs" style={{ fontSize: "12px" }}
|
||||
className="text-xs"
|
||||
style={{ fontSize: "12px" }}
|
||||
>
|
||||
<Check
|
||||
className={cn(
|
||||
|
|
@ -586,7 +610,8 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={navScreenOpen}
|
||||
className="h-6 w-full px-2 py-0 justify-between" style={{ fontSize: "12px" }}
|
||||
className="h-6 w-full justify-between px-2 py-0"
|
||||
style={{ fontSize: "12px" }}
|
||||
disabled={screensLoading}
|
||||
>
|
||||
{config.action?.targetScreenId
|
||||
|
|
@ -659,7 +684,8 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
setLocalInputs((prev) => ({ ...prev, targetUrl: newValue }));
|
||||
onUpdateProperty("componentConfig.action.targetUrl", newValue);
|
||||
}}
|
||||
className="h-6 w-full px-2 py-0 text-xs" style={{ fontSize: "12px" }}
|
||||
className="h-6 w-full px-2 py-0 text-xs"
|
||||
style={{ fontSize: "12px" }}
|
||||
/>
|
||||
<p className="mt-1 text-xs text-gray-500">URL을 입력하면 화면 선택보다 우선 적용됩니다</p>
|
||||
</div>
|
||||
|
|
@ -671,7 +697,8 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
<ImprovedButtonControlConfigPanel component={component} onUpdateProperty={onUpdateProperty} />
|
||||
</div>
|
||||
|
||||
{/* 🆕 플로우 단계별 표시 제어 섹션 */}
|
||||
{/* 🆕 플로우 단계별 표시 제어 섹션 (플로우 위젯이 있을 때만 표시) */}
|
||||
{hasFlowWidget && (
|
||||
<div className="mt-8 border-t border-gray-200 pt-6">
|
||||
<FlowVisibilityConfigPanel
|
||||
component={component}
|
||||
|
|
@ -679,6 +706,7 @@ export const ButtonConfigPanel: React.FC<ButtonConfigPanelProps> = ({
|
|||
onUpdateProperty={onUpdateProperty}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
|
|||
import { Badge } from "@/components/ui/badge";
|
||||
import { Alert, AlertDescription } from "@/components/ui/alert";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@/components/ui/card";
|
||||
import { Workflow, Info, CheckCircle, XCircle, Loader2, ArrowRight, ArrowDown } from "lucide-react";
|
||||
import { ComponentData } from "@/types/screen";
|
||||
import { FlowVisibilityConfig } from "@/types/control-management";
|
||||
|
|
@ -344,7 +345,11 @@ export const FlowVisibilityConfigPanel: React.FC<FlowVisibilityConfigPanelProps>
|
|||
checked={isChecked}
|
||||
onCheckedChange={() => toggleStep(step.id)}
|
||||
/>
|
||||
<Label htmlFor={`step-${step.id}`} className="flex flex-1 items-center gap-2 text-xs" style={{ fontSize: "12px" }}>
|
||||
<Label
|
||||
htmlFor={`step-${step.id}`}
|
||||
className="flex flex-1 items-center gap-2 text-xs"
|
||||
style={{ fontSize: "12px" }}
|
||||
>
|
||||
<Badge variant="outline" className="text-xs">
|
||||
Step {step.stepOrder}
|
||||
</Badge>
|
||||
|
|
@ -403,7 +408,8 @@ export const FlowVisibilityConfigPanel: React.FC<FlowVisibilityConfigPanelProps>
|
|||
value={groupId}
|
||||
onChange={(e) => setGroupId(e.target.value)}
|
||||
placeholder="group-1"
|
||||
className="h-6 text-xs sm:h-9 sm:text-xs" style={{ fontSize: "12px" }}
|
||||
className="h-6 text-xs sm:h-9 sm:text-xs"
|
||||
style={{ fontSize: "12px" }}
|
||||
/>
|
||||
<p className="text-muted-foreground text-[10px]">
|
||||
같은 그룹 ID를 가진 버튼들이 하나의 그룹으로 묶입니다
|
||||
|
|
@ -453,7 +459,8 @@ export const FlowVisibilityConfigPanel: React.FC<FlowVisibilityConfigPanelProps>
|
|||
setGroupGap(Number(e.target.value));
|
||||
setTimeout(() => applyConfig(), 0);
|
||||
}}
|
||||
className="h-6 text-xs sm:h-9 sm:text-xs" style={{ fontSize: "12px" }}
|
||||
className="h-6 text-xs sm:h-9 sm:text-xs"
|
||||
style={{ fontSize: "12px" }}
|
||||
/>
|
||||
<Badge variant="outline" className="text-xs">
|
||||
{groupGap}px
|
||||
|
|
@ -473,7 +480,11 @@ export const FlowVisibilityConfigPanel: React.FC<FlowVisibilityConfigPanelProps>
|
|||
setTimeout(() => applyConfig(), 0);
|
||||
}}
|
||||
>
|
||||
<SelectTrigger id="group-align" className="h-6 text-xs sm:h-9 sm:text-xs" style={{ fontSize: "12px" }}>
|
||||
<SelectTrigger
|
||||
id="group-align"
|
||||
className="h-6 text-xs sm:h-9 sm:text-xs"
|
||||
style={{ fontSize: "12px" }}
|
||||
>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ interface SingleTableWithStickyProps {
|
|||
handleSelectAll: (checked: boolean) => void;
|
||||
handleRowClick: (row: any) => void;
|
||||
renderCheckboxCell: (row: any, index: number) => React.ReactNode;
|
||||
formatCellValue: (value: any, format?: string, columnName?: string) => string;
|
||||
formatCellValue: (value: any, format?: string, columnName?: string, rowData?: Record<string, any>) => string;
|
||||
getColumnWidth: (column: ColumnConfig) => number;
|
||||
containerWidth?: string; // 컨테이너 너비 설정
|
||||
}
|
||||
|
|
@ -63,7 +63,13 @@ export const SingleTableWithSticky: React.FC<SingleTableWithStickyProps> = ({
|
|||
boxSizing: "border-box",
|
||||
}}
|
||||
>
|
||||
<TableHeader className={tableConfig.stickyHeader ? "sticky top-0 z-20 bg-gradient-to-r from-slate-50/90 to-gray-50/70 backdrop-blur-sm border-b border-gray-200/40" : "bg-gradient-to-r from-slate-50/90 to-gray-50/70 backdrop-blur-sm border-b border-gray-200/40"}>
|
||||
<TableHeader
|
||||
className={
|
||||
tableConfig.stickyHeader
|
||||
? "sticky top-0 z-20 border-b border-gray-200/40 bg-gradient-to-r from-slate-50/90 to-gray-50/70 backdrop-blur-sm"
|
||||
: "border-b border-gray-200/40 bg-gradient-to-r from-slate-50/90 to-gray-50/70 backdrop-blur-sm"
|
||||
}
|
||||
>
|
||||
<TableRow className="border-b border-gray-200/40">
|
||||
{visibleColumns.map((column, colIndex) => {
|
||||
// 왼쪽 고정 컬럼들의 누적 너비 계산
|
||||
|
|
@ -86,12 +92,14 @@ export const SingleTableWithSticky: React.FC<SingleTableWithStickyProps> = ({
|
|||
className={cn(
|
||||
column.columnName === "__checkbox__"
|
||||
? "h-12 border-0 px-6 py-4 text-center align-middle"
|
||||
: "h-12 cursor-pointer border-0 px-6 py-4 text-left align-middle font-semibold whitespace-nowrap text-gray-700 select-none transition-all duration-200 hover:text-gray-900",
|
||||
: "h-12 cursor-pointer border-0 px-6 py-4 text-left align-middle font-semibold whitespace-nowrap text-gray-700 transition-all duration-200 select-none hover:text-gray-900",
|
||||
`text-${column.align}`,
|
||||
column.sortable && "hover:bg-orange-200/70",
|
||||
// 고정 컬럼 스타일
|
||||
column.fixed === "left" && "sticky z-10 border-r border-gray-200/40 bg-gradient-to-r from-slate-50/90 to-gray-50/70 shadow-sm",
|
||||
column.fixed === "right" && "sticky z-10 border-l border-gray-200/40 bg-gradient-to-r from-slate-50/90 to-gray-50/70 shadow-sm",
|
||||
column.fixed === "left" &&
|
||||
"sticky z-10 border-r border-gray-200/40 bg-gradient-to-r from-slate-50/90 to-gray-50/70 shadow-sm",
|
||||
column.fixed === "right" &&
|
||||
"sticky z-10 border-l border-gray-200/40 bg-gradient-to-r from-slate-50/90 to-gray-50/70 shadow-sm",
|
||||
// 숨김 컬럼 스타일 (디자인 모드에서만)
|
||||
isDesignMode && column.hidden && "bg-gray-100/50 opacity-40",
|
||||
)}
|
||||
|
|
@ -112,7 +120,12 @@ export const SingleTableWithSticky: React.FC<SingleTableWithStickyProps> = ({
|
|||
<div className="flex items-center gap-2">
|
||||
{column.columnName === "__checkbox__" ? (
|
||||
checkboxConfig.selectAll && (
|
||||
<Checkbox checked={isAllSelected} onCheckedChange={handleSelectAll} aria-label="전체 선택" style={{ zIndex: 1 }} />
|
||||
<Checkbox
|
||||
checked={isAllSelected}
|
||||
onCheckedChange={handleSelectAll}
|
||||
aria-label="전체 선택"
|
||||
style={{ zIndex: 1 }}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
<>
|
||||
|
|
@ -144,11 +157,18 @@ export const SingleTableWithSticky: React.FC<SingleTableWithStickyProps> = ({
|
|||
<div className="flex flex-col items-center justify-center space-y-3">
|
||||
<div className="flex h-12 w-12 items-center justify-center rounded-full bg-gradient-to-br from-gray-100 to-gray-200">
|
||||
<svg className="h-6 w-6 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<span className="text-sm font-medium text-gray-500">데이터가 없습니다</span>
|
||||
<span className="text-xs text-gray-400 bg-gray-100 px-3 py-1 rounded-full">조건을 변경하여 다시 검색해보세요</span>
|
||||
<span className="rounded-full bg-gray-100 px-3 py-1 text-xs text-gray-400">
|
||||
조건을 변경하여 다시 검색해보세요
|
||||
</span>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
|
|
@ -158,7 +178,8 @@ export const SingleTableWithSticky: React.FC<SingleTableWithStickyProps> = ({
|
|||
key={`row-${index}`}
|
||||
className={cn(
|
||||
"h-12 cursor-pointer border-b border-gray-100/40 leading-none transition-all duration-200",
|
||||
tableConfig.tableStyle?.hoverEffect && "hover:bg-gradient-to-r hover:from-orange-50/80 hover:to-orange-100/60 hover:shadow-sm",
|
||||
tableConfig.tableStyle?.hoverEffect &&
|
||||
"hover:bg-gradient-to-r hover:from-orange-50/80 hover:to-orange-100/60 hover:shadow-sm",
|
||||
tableConfig.tableStyle?.alternateRows && index % 2 === 1 && "bg-gray-50/30",
|
||||
)}
|
||||
style={{ minHeight: "48px", height: "48px", lineHeight: "1" }}
|
||||
|
|
@ -186,8 +207,10 @@ export const SingleTableWithSticky: React.FC<SingleTableWithStickyProps> = ({
|
|||
"h-12 px-6 py-4 align-middle text-sm whitespace-nowrap text-gray-600 transition-all duration-200",
|
||||
`text-${column.align}`,
|
||||
// 고정 컬럼 스타일
|
||||
column.fixed === "left" && "sticky z-10 border-r border-gray-200/40 bg-white/90 backdrop-blur-sm",
|
||||
column.fixed === "right" && "sticky z-10 border-l border-gray-200/40 bg-white/90 backdrop-blur-sm",
|
||||
column.fixed === "left" &&
|
||||
"sticky z-10 border-r border-gray-200/40 bg-white/90 backdrop-blur-sm",
|
||||
column.fixed === "right" &&
|
||||
"sticky z-10 border-l border-gray-200/40 bg-white/90 backdrop-blur-sm",
|
||||
)}
|
||||
style={{
|
||||
minHeight: "48px",
|
||||
|
|
@ -207,7 +230,7 @@ export const SingleTableWithSticky: React.FC<SingleTableWithStickyProps> = ({
|
|||
>
|
||||
{column.columnName === "__checkbox__"
|
||||
? renderCheckboxCell(row, index)
|
||||
: formatCellValue(row[column.columnName], column.format, column.columnName) || "\u00A0"}
|
||||
: formatCellValue(row[column.columnName], column.format, column.columnName, row) || "\u00A0"}
|
||||
</TableCell>
|
||||
);
|
||||
})}
|
||||
|
|
|
|||
|
|
@ -620,9 +620,29 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
};
|
||||
|
||||
const formatCellValue = useCallback(
|
||||
(value: any, column: ColumnConfig) => {
|
||||
(value: any, column: ColumnConfig, rowData?: Record<string, any>) => {
|
||||
if (value === null || value === undefined) return "-";
|
||||
|
||||
// 🎯 엔티티 컬럼 표시 설정이 있는 경우
|
||||
if (column.entityDisplayConfig && rowData) {
|
||||
// displayColumns 또는 selectedColumns 둘 다 체크
|
||||
const displayColumns = column.entityDisplayConfig.displayColumns || column.entityDisplayConfig.selectedColumns;
|
||||
const separator = column.entityDisplayConfig.separator;
|
||||
|
||||
if (displayColumns && displayColumns.length > 0) {
|
||||
// 선택된 컬럼들의 값을 구분자로 조합
|
||||
const values = displayColumns
|
||||
.map((colName) => {
|
||||
const cellValue = rowData[colName];
|
||||
if (cellValue === null || cellValue === undefined) return "";
|
||||
return String(cellValue);
|
||||
})
|
||||
.filter((v) => v !== ""); // 빈 값 제외
|
||||
|
||||
return values.join(separator || " - ");
|
||||
}
|
||||
}
|
||||
|
||||
const meta = columnMeta[column.columnName];
|
||||
if (meta?.webType && meta?.codeCategory) {
|
||||
const convertedValue = optimizedConvertCode(value, meta.codeCategory);
|
||||
|
|
@ -908,9 +928,9 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
columnLabels={columnLabels}
|
||||
renderCheckboxHeader={renderCheckboxHeader}
|
||||
renderCheckboxCell={renderCheckboxCell}
|
||||
formatCellValue={(value: any, format?: string, columnName?: string) => {
|
||||
formatCellValue={(value: any, format?: string, columnName?: string, rowData?: Record<string, any>) => {
|
||||
const column = visibleColumns.find((c) => c.columnName === columnName);
|
||||
return column ? formatCellValue(value, column) : String(value);
|
||||
return column ? formatCellValue(value, column, rowData) : String(value);
|
||||
}}
|
||||
getColumnWidth={getColumnWidth}
|
||||
containerWidth={calculatedWidth}
|
||||
|
|
@ -1091,7 +1111,7 @@ export const TableListComponent: React.FC<TableListComponentProps> = ({
|
|||
>
|
||||
{column.columnName === "__checkbox__"
|
||||
? renderCheckboxCell(row, index)
|
||||
: formatCellValue(cellValue, column)}
|
||||
: formatCellValue(cellValue, column, row)}
|
||||
</td>
|
||||
);
|
||||
})}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue