feature/v2-unified-renewal #379
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
| 기능 | 적용 완료 | 미적용 | 해당없음 |
|
| 기능 | 적용 완료 | 미적용 | 해당없음 |
|
||||||
| -------------------------- | --------- | ------ | -------- |
|
| -------------------------- | --------- | ------ | -------- |
|
||||||
| **다국어 지원** | 3개 | 10개 | 3개 |
|
| **다국어 지원** | 3개 | 9개 | 4개 |
|
||||||
| **컴포넌트별 테이블 설정** | 6개 | 4개 | 6개 |
|
| **컴포넌트별 테이블 설정** | 6개 | 4개 | 6개 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -18,12 +18,12 @@
|
||||||
|
|
||||||
### 데이터 표시 (Display) - 4개
|
### 데이터 표시 (Display) - 4개
|
||||||
|
|
||||||
| 컴포넌트 | 다국어 지원 | 테이블 설정 | 비고 |
|
| 컴포넌트 | 다국어 지원 | 테이블 설정 | 비고 |
|
||||||
| ------------------- | :---------: | :---------: | ------------------------------------------------------------------- |
|
| ------------------- | :---------: | :---------: | --------------------------------------------- |
|
||||||
| **테이블 리스트** | ✅ 적용 | ✅ 적용 | `customTableName`, `useCustomTable` 지원 |
|
| **테이블 리스트** | ✅ 적용 | ✅ 적용 | `customTableName`, `useCustomTable` 지원 |
|
||||||
| **카드 디스플레이** | ❌ 미적용 | ✅ 적용 | Combobox UI로 테이블 선택, `customTableName`, `useCustomTable` 지원 |
|
| **카드 디스플레이** | ➖ 해당없음 | ✅ 적용 | DB 데이터 표시용, 버튼은 시스템 다국어로 처리 |
|
||||||
| **텍스트 표시** | ❌ 미적용 | ➖ 해당없음 | 정적 텍스트 표시용 |
|
| **텍스트 표시** | ❌ 미적용 | ➖ 해당없음 | 정적 텍스트 표시용 |
|
||||||
| **피벗 그리드** | ❌ 미적용 | ⚠️ 부분 | `tableName` 설정 가능하나 Combobox UI 없음 |
|
| **피벗 그리드** | ❌ 미적용 | ⚠️ 부분 | `tableName` 설정 가능하나 Combobox UI 없음 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -79,11 +79,18 @@
|
||||||
- `button-primary`: 버튼 텍스트 다국어 지원
|
- `button-primary`: 버튼 텍스트 다국어 지원
|
||||||
- `split-panel-layout`: 패널 제목 다국어 지원
|
- `split-panel-layout`: 패널 제목 다국어 지원
|
||||||
|
|
||||||
**미적용 (10개)**
|
**해당없음 (4개)**
|
||||||
|
|
||||||
- `card-display`, `text-display`, `pivot-grid`
|
- `card-display`: DB 데이터 표시용, 버튼 라벨은 시스템 다국어로 처리
|
||||||
|
- `text-display`: 정적 텍스트 표시용
|
||||||
|
- `divider-line`: 시각적 구분용
|
||||||
|
- `구분선`: 시각적 구분용
|
||||||
|
|
||||||
|
**미적용 (9개)**
|
||||||
|
|
||||||
|
- `pivot-grid`
|
||||||
- `unified-repeater`, `repeat-screen-modal`
|
- `unified-repeater`, `repeat-screen-modal`
|
||||||
- `tabs`, `section-card`, `section-paper`, `divider-line`
|
- `tabs`, `section-card`, `section-paper`
|
||||||
- `numbering-rule`, `rack-structure`, `location-swap-selector`, `table-search-widget`
|
- `numbering-rule`, `rack-structure`, `location-swap-selector`, `table-search-widget`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -131,12 +138,12 @@
|
||||||
|
|
||||||
### 2순위: 다국어 지원 확대
|
### 2순위: 다국어 지원 확대
|
||||||
|
|
||||||
| 컴포넌트 | 작업 내용 |
|
| 컴포넌트 | 작업 내용 | 상태 |
|
||||||
| ------------------ | -------------------------- |
|
| ------------------ | -------------------------- | ----------- |
|
||||||
| `unified-repeater` | 컬럼 라벨 `langKeyId` 지원 |
|
| `card-display` | 버튼 라벨 시스템 다국어 | ➖ 해당없음 |
|
||||||
| `card-display` | 필드 라벨 `langKeyId` 지원 |
|
| `unified-repeater` | 컬럼 라벨 `langKeyId` 지원 | 대기 |
|
||||||
| `tabs` | 탭 이름 `langKeyId` 지원 |
|
| `tabs` | 탭 이름 `langKeyId` 지원 | 대기 |
|
||||||
| `section-card` | 제목 `langKeyId` 지원 |
|
| `section-card` | 제목 `langKeyId` 지원 | 대기 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,6 @@ import { ScreenPreviewProvider } from "@/contexts/ScreenPreviewContext";
|
||||||
import { TableOptionsProvider } from "@/contexts/TableOptionsContext";
|
import { TableOptionsProvider } from "@/contexts/TableOptionsContext";
|
||||||
|
|
||||||
// 새로운 통합 UI 컴포넌트
|
// 새로운 통합 UI 컴포넌트
|
||||||
import { LeftUnifiedToolbar, defaultToolbarButtons } from "./toolbar/LeftUnifiedToolbar";
|
|
||||||
import { SlimToolbar } from "./toolbar/SlimToolbar";
|
import { SlimToolbar } from "./toolbar/SlimToolbar";
|
||||||
import { UnifiedPropertiesPanel } from "./panels/UnifiedPropertiesPanel";
|
import { UnifiedPropertiesPanel } from "./panels/UnifiedPropertiesPanel";
|
||||||
|
|
||||||
|
|
@ -4464,15 +4463,14 @@ export default function ScreenDesigner({ selectedScreen, onBackToList }: ScreenD
|
||||||
onGenerateMultilang={handleGenerateMultilang}
|
onGenerateMultilang={handleGenerateMultilang}
|
||||||
isGeneratingMultilang={isGeneratingMultilang}
|
isGeneratingMultilang={isGeneratingMultilang}
|
||||||
onOpenMultilangSettings={() => setShowMultilangSettingsModal(true)}
|
onOpenMultilangSettings={() => setShowMultilangSettingsModal(true)}
|
||||||
|
isPanelOpen={panelStates.unified?.isOpen || false}
|
||||||
|
onTogglePanel={() => togglePanel("unified")}
|
||||||
/>
|
/>
|
||||||
{/* 메인 컨테이너 (좌측 툴바 + 패널들 + 캔버스) */}
|
{/* 메인 컨테이너 (패널들 + 캔버스) */}
|
||||||
<div className="flex flex-1 overflow-hidden">
|
<div className="flex flex-1 overflow-hidden">
|
||||||
{/* 좌측 통합 툴바 */}
|
{/* 통합 패널 - 좌측 사이드바 제거 후 너비 300px로 확장 */}
|
||||||
<LeftUnifiedToolbar buttons={defaultToolbarButtons} panelStates={panelStates} onTogglePanel={togglePanel} />
|
|
||||||
|
|
||||||
{/* 통합 패널 */}
|
|
||||||
{panelStates.unified?.isOpen && (
|
{panelStates.unified?.isOpen && (
|
||||||
<div className="border-border bg-card flex h-full w-[240px] flex-col border-r shadow-sm overflow-hidden">
|
<div className="border-border bg-card flex h-full w-[300px] flex-col border-r shadow-sm overflow-hidden">
|
||||||
<div className="border-border flex items-center justify-between border-b px-4 py-3 shrink-0">
|
<div className="border-border flex items-center justify-between border-b px-4 py-3 shrink-0">
|
||||||
<h3 className="text-foreground text-sm font-semibold">패널</h3>
|
<h3 className="text-foreground text-sm font-semibold">패널</h3>
|
||||||
<button
|
<button
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import { Input } from "@/components/ui/input";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
import { ComponentRegistry } from "@/lib/registry/ComponentRegistry";
|
import { ComponentRegistry } from "@/lib/registry/ComponentRegistry";
|
||||||
import { ComponentDefinition, ComponentCategory } from "@/types/component";
|
import { ComponentDefinition, ComponentCategory } from "@/types/component";
|
||||||
import { Search, Package, Grid, Layers, Palette, Zap, MousePointer, Database } from "lucide-react";
|
import { Search, Package, Grid, Layers, Palette, Zap, MousePointer, Database, GripVertical } from "lucide-react";
|
||||||
import { TableInfo, ColumnInfo } from "@/types/screen";
|
import { TableInfo, ColumnInfo } from "@/types/screen";
|
||||||
import TablesPanel from "./TablesPanel";
|
import TablesPanel from "./TablesPanel";
|
||||||
|
|
||||||
|
|
@ -72,8 +72,8 @@ export function ComponentsPanel({
|
||||||
// unified-hierarchy 제거 - 현재 미사용
|
// unified-hierarchy 제거 - 현재 미사용
|
||||||
{
|
{
|
||||||
id: "unified-repeater",
|
id: "unified-repeater",
|
||||||
name: "통합 반복 데이터",
|
name: "리피터 그리드",
|
||||||
description: "반복 데이터 관리 (인라인/모달/버튼 모드)",
|
description: "행 단위로 데이터를 추가/수정/삭제",
|
||||||
category: "data" as ComponentCategory,
|
category: "data" as ComponentCategory,
|
||||||
tags: ["repeater", "table", "modal", "button", "unified"],
|
tags: ["repeater", "table", "modal", "button", "unified"],
|
||||||
defaultSize: { width: 600, height: 300 },
|
defaultSize: { width: 600, height: 300 },
|
||||||
|
|
@ -188,7 +188,25 @@ export function ComponentsPanel({
|
||||||
e.dataTransfer.effectAllowed = "copy";
|
e.dataTransfer.effectAllowed = "copy";
|
||||||
};
|
};
|
||||||
|
|
||||||
// 컴포넌트 카드 렌더링 함수
|
// 카테고리별 배경색 매핑
|
||||||
|
const getCategoryColor = (category: string) => {
|
||||||
|
switch (category) {
|
||||||
|
case "data":
|
||||||
|
return "from-blue-500/10 to-blue-600/10 text-blue-600 group-hover:from-blue-500/20 group-hover:to-blue-600/20";
|
||||||
|
case "display":
|
||||||
|
return "from-emerald-500/10 to-emerald-600/10 text-emerald-600 group-hover:from-emerald-500/20 group-hover:to-emerald-600/20";
|
||||||
|
case "input":
|
||||||
|
return "from-violet-500/10 to-violet-600/10 text-violet-600 group-hover:from-violet-500/20 group-hover:to-violet-600/20";
|
||||||
|
case "layout":
|
||||||
|
return "from-amber-500/10 to-amber-600/10 text-amber-600 group-hover:from-amber-500/20 group-hover:to-amber-600/20";
|
||||||
|
case "action":
|
||||||
|
return "from-rose-500/10 to-rose-600/10 text-rose-600 group-hover:from-rose-500/20 group-hover:to-rose-600/20";
|
||||||
|
default:
|
||||||
|
return "from-slate-500/10 to-slate-600/10 text-slate-600 group-hover:from-slate-500/20 group-hover:to-slate-600/20";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 컴포넌트 카드 렌더링 함수 (컴팩트 버전)
|
||||||
const renderComponentCard = (component: ComponentDefinition) => (
|
const renderComponentCard = (component: ComponentDefinition) => (
|
||||||
<div
|
<div
|
||||||
key={component.id}
|
key={component.id}
|
||||||
|
|
@ -202,21 +220,27 @@ export function ComponentsPanel({
|
||||||
e.currentTarget.style.opacity = "1";
|
e.currentTarget.style.opacity = "1";
|
||||||
e.currentTarget.style.transform = "none";
|
e.currentTarget.style.transform = "none";
|
||||||
}}
|
}}
|
||||||
className="group bg-card hover:border-primary/50 cursor-grab rounded-lg border p-3 shadow-sm transition-all duration-200 hover:-translate-y-0.5 hover:shadow-md active:translate-y-0 active:scale-[0.98] active:cursor-grabbing"
|
className="group bg-card hover:border-primary/40 cursor-grab rounded-lg border px-3 py-2.5 transition-all duration-200 hover:shadow-sm active:scale-[0.98] active:cursor-grabbing"
|
||||||
>
|
>
|
||||||
<div className="flex items-start gap-3">
|
<div className="flex items-center gap-2.5">
|
||||||
<div className="bg-primary/10 text-primary group-hover:bg-primary/20 flex h-10 w-10 items-center justify-center rounded-md transition-all duration-200">
|
<div
|
||||||
|
className={`flex h-8 w-8 shrink-0 items-center justify-center rounded-md bg-gradient-to-br transition-all duration-200 ${getCategoryColor(component.category)}`}
|
||||||
|
>
|
||||||
{getCategoryIcon(component.category)}
|
{getCategoryIcon(component.category)}
|
||||||
</div>
|
</div>
|
||||||
<div className="min-w-0 flex-1">
|
<div className="min-w-0 flex-1">
|
||||||
<h4 className="mb-1 text-xs leading-tight font-semibold">{component.name}</h4>
|
<span className="text-foreground block truncate text-xs font-medium">{component.name}</span>
|
||||||
<p className="text-muted-foreground mb-1.5 line-clamp-2 text-xs leading-relaxed">{component.description}</p>
|
<div className="flex items-center gap-2">
|
||||||
<div className="flex items-center">
|
<span className="text-muted-foreground text-[10px] capitalize">{component.category}</span>
|
||||||
<span className="bg-muted text-muted-foreground rounded-full px-2 py-0.5 text-xs font-medium">
|
<span className="text-muted-foreground/60 text-[10px]">|</span>
|
||||||
|
<span className="text-muted-foreground text-[10px]">
|
||||||
{component.defaultSize.width}×{component.defaultSize.height}
|
{component.defaultSize.width}×{component.defaultSize.height}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="text-muted-foreground/40 group-hover:text-muted-foreground/60 transition-colors">
|
||||||
|
<GripVertical className="h-3.5 w-3.5" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
@ -275,13 +299,13 @@ export function ComponentsPanel({
|
||||||
|
|
||||||
{/* 테이블 컬럼 탭 */}
|
{/* 테이블 컬럼 탭 */}
|
||||||
<TabsContent value="tables" className="mt-0 flex-1 overflow-y-auto">
|
<TabsContent value="tables" className="mt-0 flex-1 overflow-y-auto">
|
||||||
<TablesPanel
|
<TablesPanel
|
||||||
tables={tables}
|
tables={tables}
|
||||||
searchTerm={searchTerm}
|
searchTerm={searchTerm}
|
||||||
onSearchChange={onSearchChange || (() => {})}
|
onSearchChange={onSearchChange || (() => {})}
|
||||||
onDragStart={onTableDragStart || (() => {})}
|
onDragStart={onTableDragStart || (() => {})}
|
||||||
selectedTableName={selectedTableName}
|
selectedTableName={selectedTableName}
|
||||||
placedColumns={placedColumns}
|
placedColumns={placedColumns}
|
||||||
onTableSelect={onTableSelect}
|
onTableSelect={onTableSelect}
|
||||||
showTableSelector={showTableSelector}
|
showTableSelector={showTableSelector}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ import {
|
||||||
Zap,
|
Zap,
|
||||||
Languages,
|
Languages,
|
||||||
Settings2,
|
Settings2,
|
||||||
|
PanelLeft,
|
||||||
|
PanelLeftClose,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { ScreenResolution, SCREEN_RESOLUTIONS } from "@/types/screen";
|
import { ScreenResolution, SCREEN_RESOLUTIONS } from "@/types/screen";
|
||||||
import {
|
import {
|
||||||
|
|
@ -60,6 +62,9 @@ interface SlimToolbarProps {
|
||||||
onGenerateMultilang?: () => void;
|
onGenerateMultilang?: () => void;
|
||||||
isGeneratingMultilang?: boolean;
|
isGeneratingMultilang?: boolean;
|
||||||
onOpenMultilangSettings?: () => void;
|
onOpenMultilangSettings?: () => void;
|
||||||
|
// 패널 토글 기능
|
||||||
|
isPanelOpen?: boolean;
|
||||||
|
onTogglePanel?: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SlimToolbar: React.FC<SlimToolbarProps> = ({
|
export const SlimToolbar: React.FC<SlimToolbarProps> = ({
|
||||||
|
|
@ -76,6 +81,8 @@ export const SlimToolbar: React.FC<SlimToolbarProps> = ({
|
||||||
onGenerateMultilang,
|
onGenerateMultilang,
|
||||||
isGeneratingMultilang = false,
|
isGeneratingMultilang = false,
|
||||||
onOpenMultilangSettings,
|
onOpenMultilangSettings,
|
||||||
|
isPanelOpen = false,
|
||||||
|
onTogglePanel,
|
||||||
}) => {
|
}) => {
|
||||||
// 사용자 정의 해상도 상태
|
// 사용자 정의 해상도 상태
|
||||||
const [customWidth, setCustomWidth] = useState("");
|
const [customWidth, setCustomWidth] = useState("");
|
||||||
|
|
@ -121,13 +128,33 @@ export const SlimToolbar: React.FC<SlimToolbarProps> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-14 items-center justify-between border-b border-gray-200 bg-gradient-to-r from-gray-50 to-white px-4 shadow-sm">
|
<div className="flex h-14 items-center justify-between border-b border-gray-200 bg-gradient-to-r from-gray-50 to-white px-4 shadow-sm">
|
||||||
{/* 좌측: 네비게이션 및 화면 정보 */}
|
{/* 좌측: 네비게이션 + 패널 토글 + 화면 정보 */}
|
||||||
<div className="flex items-center space-x-4">
|
<div className="flex items-center space-x-4">
|
||||||
<Button variant="ghost" size="sm" onClick={onBack} className="flex items-center space-x-2">
|
<Button variant="ghost" size="sm" onClick={onBack} className="flex items-center space-x-2">
|
||||||
<ArrowLeft className="h-4 w-4" />
|
<ArrowLeft className="h-4 w-4" />
|
||||||
<span>목록으로</span>
|
<span>목록으로</span>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
{onTogglePanel && <div className="h-6 w-px bg-gray-300" />}
|
||||||
|
|
||||||
|
{/* 패널 토글 버튼 */}
|
||||||
|
{onTogglePanel && (
|
||||||
|
<Button
|
||||||
|
variant={isPanelOpen ? "default" : "outline"}
|
||||||
|
size="sm"
|
||||||
|
onClick={onTogglePanel}
|
||||||
|
className="flex items-center space-x-2"
|
||||||
|
title="패널 열기/닫기 (P)"
|
||||||
|
>
|
||||||
|
{isPanelOpen ? (
|
||||||
|
<PanelLeftClose className="h-4 w-4" />
|
||||||
|
) : (
|
||||||
|
<PanelLeft className="h-4 w-4" />
|
||||||
|
)}
|
||||||
|
<span>패널</span>
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="h-6 w-px bg-gray-300" />
|
<div className="h-6 w-px bg-gray-300" />
|
||||||
|
|
||||||
<div className="flex items-center space-x-3">
|
<div className="flex items-center space-x-3">
|
||||||
|
|
|
||||||
|
|
@ -760,130 +760,6 @@ export const TableListConfigPanel: React.FC<TableListConfigPanelProps> = ({
|
||||||
<div className="text-sm font-medium">테이블 리스트 설정</div>
|
<div className="text-sm font-medium">테이블 리스트 설정</div>
|
||||||
|
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
{/* 커스텀 테이블 설정 */}
|
|
||||||
<div className="space-y-3">
|
|
||||||
<div>
|
|
||||||
<h3 className="text-sm font-semibold">데이터 소스 테이블</h3>
|
|
||||||
<p className="text-muted-foreground text-[10px]">화면 메인 테이블과 다른 테이블을 사용할 수 있습니다</p>
|
|
||||||
</div>
|
|
||||||
<hr className="border-border" />
|
|
||||||
|
|
||||||
{/* 커스텀 테이블 사용 여부 */}
|
|
||||||
{/* 현재 선택된 테이블 표시 (카드 형태) */}
|
|
||||||
<div className="flex items-center gap-2 rounded-md border bg-slate-50 p-2">
|
|
||||||
<Database className="h-4 w-4 text-blue-500" />
|
|
||||||
<div className="flex-1">
|
|
||||||
<div className="text-xs font-medium">
|
|
||||||
{config.customTableName || config.selectedTable || screenTableName || "테이블 미선택"}
|
|
||||||
</div>
|
|
||||||
<div className="text-[10px] text-muted-foreground">
|
|
||||||
{config.useCustomTable ? "커스텀 테이블" : "화면 기본 테이블"}
|
|
||||||
{config.isReadOnly && " (읽기전용)"}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 테이블 선택 Combobox (기본/전체 그룹) */}
|
|
||||||
<Popover open={tableComboboxOpen} onOpenChange={setTableComboboxOpen}>
|
|
||||||
<PopoverTrigger asChild>
|
|
||||||
<Button
|
|
||||||
variant="outline"
|
|
||||||
role="combobox"
|
|
||||||
aria-expanded={tableComboboxOpen}
|
|
||||||
className="h-8 w-full justify-between text-xs"
|
|
||||||
disabled={loadingTables}
|
|
||||||
>
|
|
||||||
테이블 변경...
|
|
||||||
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
|
||||||
</Button>
|
|
||||||
</PopoverTrigger>
|
|
||||||
<PopoverContent className="w-full p-0" align="start">
|
|
||||||
<Command>
|
|
||||||
<CommandInput placeholder="테이블 검색..." className="h-8 text-xs" />
|
|
||||||
<CommandList>
|
|
||||||
<CommandEmpty className="py-2 text-xs">테이블을 찾을 수 없습니다</CommandEmpty>
|
|
||||||
|
|
||||||
{/* 그룹 1: 화면 기본 테이블 */}
|
|
||||||
{screenTableName && (
|
|
||||||
<CommandGroup heading="기본 (화면 테이블)">
|
|
||||||
<CommandItem
|
|
||||||
key={`default-${screenTableName}`}
|
|
||||||
value={screenTableName}
|
|
||||||
onSelect={(currentValue) => {
|
|
||||||
console.log("🔍 기본 테이블 선택:", currentValue, screenTableName);
|
|
||||||
onChange({
|
|
||||||
...config,
|
|
||||||
useCustomTable: false,
|
|
||||||
customTableName: undefined,
|
|
||||||
selectedTable: screenTableName,
|
|
||||||
columns: [],
|
|
||||||
});
|
|
||||||
setTableComboboxOpen(false);
|
|
||||||
}}
|
|
||||||
className="text-xs cursor-pointer"
|
|
||||||
>
|
|
||||||
<Check
|
|
||||||
className={cn(
|
|
||||||
"mr-2 h-3 w-3",
|
|
||||||
!config.useCustomTable && (config.selectedTable === screenTableName || !config.selectedTable)
|
|
||||||
? "opacity-100"
|
|
||||||
: "opacity-0",
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<Database className="mr-2 h-3 w-3 text-blue-500" />
|
|
||||||
{screenTableName}
|
|
||||||
</CommandItem>
|
|
||||||
</CommandGroup>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* 그룹 2: 전체 테이블 */}
|
|
||||||
<CommandGroup heading="전체 테이블">
|
|
||||||
{availableTables
|
|
||||||
.filter((table) => table.tableName !== screenTableName)
|
|
||||||
.map((table) => (
|
|
||||||
<CommandItem
|
|
||||||
key={table.tableName}
|
|
||||||
value={table.tableName}
|
|
||||||
onSelect={(currentValue) => {
|
|
||||||
console.log("🔍 전체 테이블 선택:", currentValue, table.tableName);
|
|
||||||
onChange({
|
|
||||||
...config,
|
|
||||||
useCustomTable: true,
|
|
||||||
customTableName: table.tableName,
|
|
||||||
selectedTable: table.tableName,
|
|
||||||
columns: [],
|
|
||||||
});
|
|
||||||
setTableComboboxOpen(false);
|
|
||||||
}}
|
|
||||||
className="text-xs cursor-pointer"
|
|
||||||
>
|
|
||||||
<Check
|
|
||||||
className={cn(
|
|
||||||
"mr-2 h-3 w-3",
|
|
||||||
config.customTableName === table.tableName ? "opacity-100" : "opacity-0",
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<Table2 className="mr-2 h-3 w-3 text-slate-400" />
|
|
||||||
{table.displayName || table.tableName}
|
|
||||||
</CommandItem>
|
|
||||||
))}
|
|
||||||
</CommandGroup>
|
|
||||||
</CommandList>
|
|
||||||
</Command>
|
|
||||||
</PopoverContent>
|
|
||||||
</Popover>
|
|
||||||
|
|
||||||
{/* 읽기전용 설정 */}
|
|
||||||
<div className="flex items-center space-x-2">
|
|
||||||
<Checkbox
|
|
||||||
id="isReadOnly"
|
|
||||||
checked={config.isReadOnly || false}
|
|
||||||
onCheckedChange={(checked) => handleChange("isReadOnly", checked)}
|
|
||||||
/>
|
|
||||||
<Label htmlFor="isReadOnly" className="text-xs">읽기전용 (조회만 가능)</Label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 툴바 버튼 설정 */}
|
{/* 툴바 버튼 설정 */}
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<div>
|
<div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue