조회 테이블 설정 UI 표준을 추가하고, 테이블 선택 Combobox 및 읽기전용 설정 기능을 구현했습니다. 또한, 테이블 이름 계산 로직을 개선하여 커스텀 테이블 사용 시 올바른 테이블 이름을 표시하도록 수정했습니다.

This commit is contained in:
kjs 2026-01-15 16:21:55 +09:00
parent e168753d87
commit e937ba9161
3 changed files with 338 additions and 764 deletions

View File

@ -67,7 +67,90 @@ interface UnifiedRepeaterConfig {
}
```
### 저장 테이블 설정 UI 표준
### 조회 테이블 설정 UI 표준 (테이블 리스트)
테이블 리스트 등 조회용 컴포넌트의 ConfigPanel에서:
```tsx
// 현재 선택된 테이블 카드 형태로 표시
<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 || screenTableName || "테이블 미선택"}
</div>
<div className="text-[10px] text-muted-foreground">
{config.useCustomTable ? "커스텀 테이블" : "화면 기본 테이블"}
</div>
</div>
</div>
// 테이블 선택 Combobox (기본/전체 그룹)
<Popover>
<PopoverTrigger asChild>
<Button variant="outline" className="w-full justify-between">
테이블 변경...
<ChevronsUpDown className="ml-2 h-4 w-4" />
</Button>
</PopoverTrigger>
<PopoverContent className="p-0">
<Command>
<CommandInput placeholder="테이블 검색..." />
<CommandList>
{/* 그룹 1: 화면 기본 테이블 */}
{screenTableName && (
<CommandGroup heading="기본 (화면 테이블)">
<CommandItem
value={screenTableName}
onSelect={() => {
handleChange("useCustomTable", false);
handleChange("customTableName", undefined);
handleChange("selectedTable", screenTableName);
handleChange("columns", []); // 테이블 변경 시 컬럼 초기화
}}
>
<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={() => {
handleChange("useCustomTable", true);
handleChange("customTableName", table.tableName);
handleChange("selectedTable", table.tableName);
handleChange("columns", []); // 테이블 변경 시 컬럼 초기화
}}
>
<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
checked={config.isReadOnly || false}
onCheckedChange={(checked) => handleChange("isReadOnly", checked)}
/>
<Label className="text-xs">읽기전용 (조회만 가능)</Label>
</div>
```
### 저장 테이블 설정 UI 표준 (리피터)
리피터 등 저장 기능이 있는 컴포넌트의 ConfigPanel에서:

View File

@ -4076,12 +4076,17 @@ export class TableManagementService {
// table_type_columns에서 입력타입 정보 조회
// 회사별 설정 우선, 없으면 기본 설정(*) fallback
// detail_settings 컬럼에 유효하지 않은 JSON이 있을 수 있으므로 안전하게 처리
const rawInputTypes = await query<any>(
`SELECT DISTINCT ON (ttc.column_name)
ttc.column_name as "columnName",
COALESCE(cl.column_label, ttc.column_name) as "displayName",
ttc.input_type as "inputType",
COALESCE(ttc.detail_settings::jsonb, '{}'::jsonb) as "detailSettings",
CASE
WHEN ttc.detail_settings IS NULL OR ttc.detail_settings = '' THEN '{}'::jsonb
WHEN ttc.detail_settings ~ '^\\s*\\{.*\\}\\s*$' THEN ttc.detail_settings::jsonb
ELSE '{}'::jsonb
END as "detailSettings",
ttc.is_nullable as "isNullable",
ic.data_type as "dataType",
ttc.company_code as "companyCode"