refactor: 코드 정리 및 불필요한 주석 제거
- EntityJoinController에서 중복 제거 설정 관련 주석 및 코드 삭제 - screenGroupController와 tableManagementController에서 AuthenticatedRequest 타입을 일반 Request로 변경 - 불필요한 로그 및 주석 제거로 코드 가독성 향상 - tableManagementController에서 에러 메시지 개선
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -365,7 +365,6 @@ export const InteractiveScreenViewerDynamic: React.FC<InteractiveScreenViewerPro
|
||||
isInteractive={true}
|
||||
formData={formData}
|
||||
originalData={originalData || undefined}
|
||||
initialData={(originalData && Object.keys(originalData).length > 0) ? originalData : formData} // 🆕 originalData가 있으면 사용, 없으면 formData 사용 (생성 모드에서 부모 데이터 전달)
|
||||
onFormDataChange={handleFormDataChange}
|
||||
screenId={screenInfo?.id}
|
||||
tableName={screenInfo?.tableName}
|
||||
|
||||
@@ -416,6 +416,10 @@ export function ScreenSettingModal({
|
||||
<Database className="h-3 w-3" />
|
||||
개요
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="table-setting" className="gap-1 text-xs px-2" disabled={!mainTable}>
|
||||
<Settings2 className="h-3 w-3" />
|
||||
테이블 설정
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="control-management" className="gap-1 text-xs px-2">
|
||||
<Zap className="h-3 w-3" />
|
||||
제어 관리
|
||||
@@ -466,7 +470,22 @@ export function ScreenSettingModal({
|
||||
/>
|
||||
</TabsContent>
|
||||
|
||||
{/* 탭 2: 제어 관리 */}
|
||||
{/* 탭 2: 테이블 설정 */}
|
||||
<TabsContent value="table-setting" className="mt-0 min-h-0 flex-1 overflow-hidden p-0">
|
||||
{mainTable && (
|
||||
<TableSettingModal
|
||||
isOpen={true}
|
||||
onClose={() => {}} // 탭에서는 닫기 불필요
|
||||
tableName={mainTable}
|
||||
tableLabel={mainTableLabel}
|
||||
screenId={currentScreenId}
|
||||
onSaveSuccess={handleRefresh}
|
||||
isEmbedded={true} // 임베드 모드
|
||||
/>
|
||||
)}
|
||||
</TabsContent>
|
||||
|
||||
{/* 탭 3: 제어 관리 */}
|
||||
<TabsContent value="control-management" className="mt-0 min-h-0 flex-1 overflow-auto p-3">
|
||||
<ControlManagementTab
|
||||
screenId={currentScreenId}
|
||||
@@ -2198,17 +2217,6 @@ function OverviewTab({
|
||||
<Database className="h-4 w-4 text-blue-500" />
|
||||
메인 테이블
|
||||
</h3>
|
||||
{mainTable && (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="h-7 gap-1 text-xs"
|
||||
onClick={() => onOpenTableSetting?.(mainTable, mainTableLabel)}
|
||||
>
|
||||
<Settings2 className="h-3 w-3" />
|
||||
테이블 설정
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
{mainTable ? (
|
||||
<TableColumnAccordion
|
||||
@@ -3049,6 +3057,7 @@ interface ButtonControlInfo {
|
||||
// 버튼 스타일
|
||||
backgroundColor?: string;
|
||||
textColor?: string;
|
||||
borderRadius?: string;
|
||||
// 모달/네비게이션 관련
|
||||
modalScreenId?: number;
|
||||
navigateScreenId?: number;
|
||||
@@ -3215,6 +3224,7 @@ function ControlManagementTab({
|
||||
// 버튼 스타일 (webTypeConfig 우선)
|
||||
backgroundColor: webTypeConfig.backgroundColor || config.backgroundColor || style.backgroundColor,
|
||||
textColor: webTypeConfig.textColor || config.textColor || style.color || style.labelColor,
|
||||
borderRadius: webTypeConfig.borderRadius || config.borderRadius || style.borderRadius,
|
||||
// 모달/네비게이션 관련 (화면 디자이너는 targetScreenId 사용)
|
||||
modalScreenId: action.targetScreenId || action.modalScreenId,
|
||||
navigateScreenId: action.navigateScreenId || action.targetScreenId,
|
||||
@@ -3527,6 +3537,11 @@ function ControlManagementTab({
|
||||
comp.style.color = values.textColor;
|
||||
comp.style.labelColor = values.textColor;
|
||||
}
|
||||
if (values.borderRadius !== undefined) {
|
||||
comp.webTypeConfig.borderRadius = values.borderRadius;
|
||||
comp.componentConfig.borderRadius = values.borderRadius;
|
||||
comp.style.borderRadius = values.borderRadius;
|
||||
}
|
||||
|
||||
// 액션 타입 업데이트
|
||||
if (values.actionType) {
|
||||
@@ -3735,6 +3750,7 @@ function ControlManagementTab({
|
||||
const currentLabel = editedValues[btn.id]?.label ?? btn.label;
|
||||
const currentBgColor = editedValues[btn.id]?.backgroundColor ?? btn.backgroundColor ?? "#3b82f6";
|
||||
const currentTextColor = editedValues[btn.id]?.textColor ?? btn.textColor ?? "#ffffff";
|
||||
const currentBorderRadius = editedValues[btn.id]?.borderRadius ?? btn.borderRadius ?? "4px";
|
||||
|
||||
return (
|
||||
<div key={btn.id} className="py-3 px-1">
|
||||
@@ -3742,10 +3758,11 @@ function ControlManagementTab({
|
||||
<div className="flex items-center gap-3 mb-3">
|
||||
{/* 버튼 프리뷰 */}
|
||||
<div
|
||||
className="flex items-center justify-center px-3 py-1.5 rounded text-xs font-medium min-w-[60px] shrink-0"
|
||||
className="flex items-center justify-center px-3 py-1.5 text-xs font-medium min-w-[60px] shrink-0"
|
||||
style={{
|
||||
backgroundColor: currentBgColor,
|
||||
color: currentTextColor,
|
||||
borderRadius: currentBorderRadius,
|
||||
}}
|
||||
>
|
||||
{currentLabel || "버튼"}
|
||||
@@ -3870,6 +3887,34 @@ function ControlManagementTab({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 버튼 모서리 (borderRadius) */}
|
||||
<div className="grid grid-cols-[80px_1fr] items-center gap-2">
|
||||
<Label className="text-xs text-muted-foreground">모서리</Label>
|
||||
<div className="flex items-center gap-2">
|
||||
<Select
|
||||
value={editedValues[btn.id]?.borderRadius ?? btn.borderRadius ?? "4px"}
|
||||
onValueChange={(val) => setEditedValues(prev => ({
|
||||
...prev,
|
||||
[btn.id]: { ...prev[btn.id], borderRadius: val }
|
||||
}))}
|
||||
>
|
||||
<SelectTrigger className="h-7 w-[100px] text-xs">
|
||||
<SelectValue placeholder="선택" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="0px" className="text-xs">없음 (0px)</SelectItem>
|
||||
<SelectItem value="2px" className="text-xs">약간 (2px)</SelectItem>
|
||||
<SelectItem value="4px" className="text-xs">기본 (4px)</SelectItem>
|
||||
<SelectItem value="6px" className="text-xs">둥글게 (6px)</SelectItem>
|
||||
<SelectItem value="8px" className="text-xs">더 둥글게 (8px)</SelectItem>
|
||||
<SelectItem value="12px" className="text-xs">많이 (12px)</SelectItem>
|
||||
<SelectItem value="9999px" className="text-xs">원형</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<span className="text-[10px] text-muted-foreground">버튼 모서리 둥글기</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 확인 메시지 설정 (save/delete 액션에서만 표시) */}
|
||||
{((editedValues[btn.id]?.actionType || btn.actionType) === "save" ||
|
||||
(editedValues[btn.id]?.actionType || btn.actionType) === "delete") && (
|
||||
|
||||
@@ -129,6 +129,7 @@ interface TableSettingModalProps {
|
||||
columns?: ColumnInfo[];
|
||||
filterColumns?: string[];
|
||||
onSaveSuccess?: () => void;
|
||||
isEmbedded?: boolean; // 탭 안에 임베드 모드로 표시
|
||||
}
|
||||
|
||||
// 검색 가능한 Select 컴포넌트
|
||||
@@ -256,6 +257,7 @@ export function TableSettingModal({
|
||||
columns = [],
|
||||
filterColumns = [],
|
||||
onSaveSuccess,
|
||||
isEmbedded = false,
|
||||
}: TableSettingModalProps) {
|
||||
const [activeTab, setActiveTab] = useState("columns");
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -304,9 +306,19 @@ export function TableSettingModal({
|
||||
// 초기 편집 상태 설정
|
||||
const initialEdits: Record<string, Partial<ColumnTypeInfo>> = {};
|
||||
columnsData.forEach((col) => {
|
||||
// referenceTable이 설정되어 있으면 inputType은 entity여야 함
|
||||
let effectiveInputType = col.inputType || "direct";
|
||||
if (col.referenceTable && effectiveInputType !== "entity") {
|
||||
effectiveInputType = "entity";
|
||||
}
|
||||
// codeCategory/codeValue가 설정되어 있으면 inputType은 code여야 함
|
||||
if (col.codeCategory && effectiveInputType !== "code") {
|
||||
effectiveInputType = "code";
|
||||
}
|
||||
|
||||
initialEdits[col.columnName] = {
|
||||
displayName: col.displayName,
|
||||
inputType: col.inputType || "direct",
|
||||
inputType: effectiveInputType,
|
||||
referenceTable: col.referenceTable,
|
||||
referenceColumn: col.referenceColumn,
|
||||
displayColumn: col.displayColumn,
|
||||
@@ -343,10 +355,10 @@ export function TableSettingModal({
|
||||
try {
|
||||
// 모든 화면 조회
|
||||
const screensResponse = await screenApi.getScreens({ size: 1000 });
|
||||
if (screensResponse.items) {
|
||||
if (screensResponse.data) {
|
||||
const usingScreens: ScreenUsingTable[] = [];
|
||||
|
||||
screensResponse.items.forEach((screen: any) => {
|
||||
screensResponse.data.forEach((screen: any) => {
|
||||
// 메인 테이블로 사용하는 경우
|
||||
if (screen.tableName === tableName) {
|
||||
usingScreens.push({
|
||||
@@ -418,6 +430,35 @@ export function TableSettingModal({
|
||||
},
|
||||
}));
|
||||
|
||||
// 입력 타입 변경 시 관련 필드 초기화
|
||||
if (field === "inputType") {
|
||||
// 엔티티가 아닌 다른 타입으로 변경하면 참조 설정 초기화
|
||||
if (value !== "entity") {
|
||||
setEditedColumns((prev) => ({
|
||||
...prev,
|
||||
[columnName]: {
|
||||
...prev[columnName],
|
||||
inputType: value,
|
||||
referenceTable: "",
|
||||
referenceColumn: "",
|
||||
displayColumn: "",
|
||||
},
|
||||
}));
|
||||
}
|
||||
// 코드가 아닌 다른 타입으로 변경하면 코드 설정 초기화
|
||||
if (value !== "code") {
|
||||
setEditedColumns((prev) => ({
|
||||
...prev,
|
||||
[columnName]: {
|
||||
...prev[columnName],
|
||||
inputType: value,
|
||||
codeCategory: "",
|
||||
codeValue: "",
|
||||
},
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
// 참조 테이블 변경 시 참조 컬럼 초기화
|
||||
if (field === "referenceTable") {
|
||||
setEditedColumns((prev) => ({
|
||||
@@ -452,8 +493,18 @@ export function TableSettingModal({
|
||||
|
||||
// detailSettings 처리 (Entity 타입인 경우)
|
||||
let finalDetailSettings = mergedColumn.detailSettings || "";
|
||||
|
||||
// referenceTable이 설정되어 있으면 inputType을 entity로 자동 설정
|
||||
let currentInputType = (mergedColumn.inputType || "") as string;
|
||||
if (mergedColumn.referenceTable && currentInputType !== "entity") {
|
||||
currentInputType = "entity";
|
||||
}
|
||||
// codeCategory가 설정되어 있으면 inputType을 code로 자동 설정
|
||||
if (mergedColumn.codeCategory && currentInputType !== "code") {
|
||||
currentInputType = "code";
|
||||
}
|
||||
|
||||
if (mergedColumn.inputType === "entity" && mergedColumn.referenceTable) {
|
||||
if (currentInputType === "entity" && mergedColumn.referenceTable) {
|
||||
// 기존 detailSettings를 파싱하거나 새로 생성
|
||||
let existingSettings: Record<string, unknown> = {};
|
||||
if (typeof mergedColumn.detailSettings === "string" && mergedColumn.detailSettings.trim().startsWith("{")) {
|
||||
@@ -479,7 +530,7 @@ export function TableSettingModal({
|
||||
}
|
||||
|
||||
// Code 타입인 경우 hierarchyRole을 detailSettings에 포함
|
||||
if (mergedColumn.inputType === "code" && (mergedColumn as any).hierarchyRole) {
|
||||
if (currentInputType === "code" && (mergedColumn as any).hierarchyRole) {
|
||||
let existingSettings: Record<string, unknown> = {};
|
||||
if (typeof finalDetailSettings === "string" && finalDetailSettings.trim().startsWith("{")) {
|
||||
try {
|
||||
@@ -502,7 +553,7 @@ export function TableSettingModal({
|
||||
const columnSetting: ColumnSettings = {
|
||||
columnName: columnName,
|
||||
columnLabel: mergedColumn.displayName || originalColumn.displayName || "",
|
||||
webType: mergedColumn.inputType || originalColumn.inputType || "text",
|
||||
inputType: currentInputType || "text", // referenceTable/codeCategory가 설정된 경우 자동 보정된 값 사용
|
||||
detailSettings: finalDetailSettings,
|
||||
codeCategory: mergedColumn.codeCategory || originalColumn.codeCategory || "",
|
||||
codeValue: mergedColumn.codeValue || originalColumn.codeValue || "",
|
||||
@@ -593,6 +644,158 @@ export function TableSettingModal({
|
||||
];
|
||||
};
|
||||
|
||||
// 임베드 모드
|
||||
if (isEmbedded) {
|
||||
return (
|
||||
<>
|
||||
<div className="flex h-full flex-col">
|
||||
{/* 헤더 */}
|
||||
<div className="flex flex-shrink-0 items-center justify-between border-b pb-2 px-3 pt-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<Table2 className="h-4 w-4 text-green-500" />
|
||||
<span className="text-sm font-medium">{tableLabel || tableName}</span>
|
||||
{tableName !== tableLabel && tableName !== (tableLabel || tableName) && (
|
||||
<span className="text-xs text-muted-foreground">({tableName})</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setShowTableManagementModal(true)}
|
||||
className="h-7 gap-1 text-xs"
|
||||
>
|
||||
<Settings className="h-3 w-3" />
|
||||
테이블 타입 관리
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={handleRefresh}
|
||||
className="h-7 w-7 p-0"
|
||||
disabled={loading}
|
||||
>
|
||||
<RefreshCw className={cn("h-3 w-3", loading && "animate-spin")} />
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
onClick={handleSaveAll}
|
||||
className="h-7 gap-1 text-xs"
|
||||
disabled={saving || loading}
|
||||
>
|
||||
{saving ? (
|
||||
<Loader2 className="h-3 w-3 animate-spin" />
|
||||
) : (
|
||||
<Save className="h-3 w-3" />
|
||||
)}
|
||||
저장
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex min-h-0 flex-1 gap-3 p-3">
|
||||
{/* 좌측: 탭 (40%) */}
|
||||
<div className="flex w-[40%] min-h-0 flex-col">
|
||||
<Tabs
|
||||
value={activeTab}
|
||||
onValueChange={setActiveTab}
|
||||
className="flex min-h-0 flex-1 flex-col"
|
||||
>
|
||||
<TabsList className="h-8 flex-shrink-0">
|
||||
<TabsTrigger value="columns" className="gap-1 text-xs">
|
||||
<Columns3 className="h-3 w-3" />
|
||||
컬럼 설정
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="screens" className="gap-1 text-xs">
|
||||
<Monitor className="h-3 w-3" />
|
||||
화면 연동
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="references" className="gap-1 text-xs">
|
||||
<Eye className="h-3 w-3" />
|
||||
참조 관계
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="columns" className="mt-2 min-h-0 flex-1 overflow-hidden">
|
||||
<ColumnListTab
|
||||
columns={tableColumns.map((col) => ({
|
||||
...col,
|
||||
isPK: col.columnName === "id" || col.columnName.endsWith("_id"),
|
||||
isFK: (col.inputType as string) === "entity",
|
||||
}))}
|
||||
editedColumns={editedColumns}
|
||||
selectedColumn={selectedColumn}
|
||||
onSelectColumn={setSelectedColumn}
|
||||
loading={loading}
|
||||
/>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="screens" className="mt-2 min-h-0 flex-1 overflow-hidden">
|
||||
<ScreensTab screensUsingTable={screensUsingTable} loading={loading} />
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="references" className="mt-2 min-h-0 flex-1 overflow-hidden">
|
||||
<ReferenceTab
|
||||
tableName={tableName}
|
||||
tableLabel={tableLabel}
|
||||
referencedBy={referencedBy}
|
||||
joinColumnRefs={joinColumnRefs}
|
||||
loading={loading}
|
||||
/>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
|
||||
{/* 우측: 상세 설정 (60%) */}
|
||||
<div className="flex w-[60%] min-h-0 flex-col rounded-lg border bg-muted/30 p-3">
|
||||
{selectedColumn && mergedColumns.find((c) => c.columnName === selectedColumn) ? (
|
||||
<ColumnDetailPanel
|
||||
columnInfo={mergedColumns.find((c) => c.columnName === selectedColumn)!}
|
||||
editedColumn={editedColumns[selectedColumn] || {}}
|
||||
tableOptions={tableOptions}
|
||||
inputTypeOptions={inputTypeOptions}
|
||||
getRefColumnOptions={getRefColumnOptions}
|
||||
loadingRefColumns={loadingRefColumns}
|
||||
onColumnChange={(field, value) => handleColumnChange(selectedColumn, field, value)}
|
||||
/>
|
||||
) : (
|
||||
<div className="flex h-full items-center justify-center text-sm text-muted-foreground">
|
||||
<div className="text-center">
|
||||
<Columns3 className="mx-auto h-12 w-12 text-muted-foreground/30" />
|
||||
<p className="mt-2">왼쪽에서 컬럼을 선택하면</p>
|
||||
<p>상세 설정을 할 수 있습니다.</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 테이블 타입 관리 모달 */}
|
||||
<Dialog open={showTableManagementModal} onOpenChange={setShowTableManagementModal}>
|
||||
<DialogContent className="flex h-[90vh] max-h-[1000px] w-[95vw] max-w-[1400px] flex-col p-0">
|
||||
<div className="flex items-center justify-between border-b p-4">
|
||||
<h2 className="text-lg font-semibold">테이블 타입 관리</h2>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
setShowTableManagementModal(false);
|
||||
loadTableData();
|
||||
}}
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex-1 overflow-hidden">
|
||||
<TableManagementPage />
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
// 기존 모달 모드
|
||||
return (
|
||||
<>
|
||||
<Dialog open={isOpen} onOpenChange={onClose}>
|
||||
@@ -843,6 +1046,7 @@ function ColumnListTab({
|
||||
<div className="space-y-1 px-3 pb-3">
|
||||
{filteredColumns.map((col) => {
|
||||
const edited = editedColumns[col.columnName] || {};
|
||||
// editedColumns에서 inputType을 가져옴 (초기화 시 이미 보정됨)
|
||||
const inputType = (edited.inputType || col.inputType || "text") as string;
|
||||
const isSelected = selectedColumn === col.columnName;
|
||||
|
||||
@@ -873,23 +1077,17 @@ function ColumnListTab({
|
||||
PK
|
||||
</Badge>
|
||||
)}
|
||||
{col.isFK && (
|
||||
<Badge variant="outline" className="bg-green-100 text-green-700 text-[10px] px-1.5">
|
||||
<Link2 className="mr-0.5 h-2.5 w-2.5" />
|
||||
FK
|
||||
</Badge>
|
||||
)}
|
||||
{(edited.referenceTable || col.referenceTable) && (
|
||||
{/* 엔티티 타입이거나 referenceTable이 설정되어 있으면 조인 배지 표시 (FK와 동일 의미) */}
|
||||
{(inputType === "entity" || edited.referenceTable || col.referenceTable) && (
|
||||
<Badge variant="outline" className="bg-blue-100 text-blue-700 text-[10px] px-1.5">
|
||||
<Link2 className="mr-0.5 h-2.5 w-2.5" />
|
||||
조인
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-1 flex items-center gap-2 text-xs text-muted-foreground">
|
||||
<div className="mt-1 text-xs text-muted-foreground">
|
||||
<span className="font-mono">{col.columnName}</span>
|
||||
<span>•</span>
|
||||
<span>{col.dataType}</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -925,10 +1123,11 @@ function ColumnDetailPanel({
|
||||
onColumnChange,
|
||||
}: ColumnDetailPanelProps) {
|
||||
const currentLabel = editedColumn.displayName ?? columnInfo.displayName ?? "";
|
||||
const currentInputType = (editedColumn.inputType ?? columnInfo.inputType ?? "text") as string;
|
||||
const currentRefTable = editedColumn.referenceTable ?? columnInfo.referenceTable ?? "";
|
||||
const currentRefColumn = editedColumn.referenceColumn ?? columnInfo.referenceColumn ?? "";
|
||||
const currentDisplayColumn = editedColumn.displayColumn ?? columnInfo.displayColumn ?? "";
|
||||
// editedColumn에서 inputType을 가져옴 (초기화 시 이미 보정됨)
|
||||
const currentInputType = (editedColumn.inputType ?? columnInfo.inputType ?? "text") as string;
|
||||
|
||||
return (
|
||||
<div className="flex h-full flex-col">
|
||||
@@ -948,9 +1147,10 @@ function ColumnDetailPanel({
|
||||
Primary Key
|
||||
</Badge>
|
||||
)}
|
||||
{columnInfo.isFK && (
|
||||
<Badge variant="outline" className="bg-green-100 text-green-700 text-[10px]">
|
||||
Foreign Key
|
||||
{/* 엔티티 타입이거나 referenceTable이 있으면 조인 배지 표시 */}
|
||||
{(currentInputType === "entity" || currentRefTable) && (
|
||||
<Badge variant="outline" className="bg-blue-100 text-blue-700 text-[10px]">
|
||||
조인
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user