From 3fa410cbe4a387d1c58f67be51b07d18cc160aec Mon Sep 17 00:00:00 2001 From: leeheejin Date: Thu, 2 Oct 2025 14:34:15 +0900 Subject: [PATCH] =?UTF-8?q?ui=20=EC=88=98=EC=A0=95=20=EB=B0=8F=20=EC=8B=9C?= =?UTF-8?q?=ED=98=84=ED=95=A0=20=EA=B8=B0=EB=8A=A5=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/routes/mailAccountFileRoutes.ts | 4 + .../src/routes/mailReceiveBasicRoutes.ts | 4 + .../src/routes/mailSendSimpleRoutes.ts | 4 + .../src/routes/mailTemplateFileRoutes.ts | 4 + .../app/(main)/admin/mail/dashboard/page.tsx | 15 +- frontend/app/(main)/admin/screenMng/page.tsx | 4 +- .../app/(main)/admin/validation-demo/page.tsx | 12 +- .../app/(main)/screens/[screenId]/page.tsx | 7 +- frontend/components/GlobalFileViewer.tsx | 8 +- frontend/components/admin/BatchJobModal.tsx | 14 +- frontend/components/admin/CategoryItem.tsx | 4 +- .../admin/CodeCategoryFormModal.tsx | 38 +- .../components/admin/CodeCategoryPanel.tsx | 4 +- frontend/components/admin/CodeDetailPanel.tsx | 8 +- frontend/components/admin/CodeFormModal.tsx | 20 +- .../admin/ColumnDefinitionTable.tsx | 4 +- .../components/admin/CreateTableModal.tsx | 2 +- frontend/components/admin/DDLLogViewer.tsx | 14 +- .../components/admin/DiskUsageSummary.tsx | 2 +- .../admin/ExternalDbConnectionModal.tsx | 4 +- frontend/components/admin/LayoutFormModal.tsx | 24 +- frontend/components/admin/MenuFormModal.tsx | 6 +- frontend/components/admin/MenuManagement.tsx | 12 +- frontend/components/admin/MenuTable.tsx | 8 +- .../components/admin/MonitoringDashboard.tsx | 12 +- frontend/components/admin/MultiLang.tsx | 10 +- .../components/admin/ScreenAssignmentTab.tsx | 12 +- .../components/admin/SortableCodeItem.tsx | 4 +- frontend/components/admin/UserFormModal.tsx | 8 +- .../admin/UserPasswordResetModal.tsx | 2 +- .../admin/UserStatusConfirmDialog.tsx | 6 +- .../admin/dashboard/CanvasElement.tsx | 6 +- .../admin/dashboard/ChartConfigPanel.tsx | 6 +- .../admin/dashboard/DashboardCanvas.tsx | 2 +- .../admin/dashboard/DashboardDesigner.tsx | 4 +- .../admin/dashboard/DashboardSidebar.tsx | 2 +- .../admin/dashboard/ElementConfigModal.tsx | 12 +- .../admin/dashboard/QueryEditor.tsx | 12 +- frontend/components/auth/AuthGuard.tsx | 8 +- frontend/components/auth/ErrorMessage.tsx | 2 +- frontend/components/auth/LoginHeader.tsx | 14 +- frontend/components/common/DataTable.tsx | 2 +- frontend/components/common/ScreenModal.tsx | 100 ++--- .../components/common/ValidationMessage.tsx | 2 +- .../components/dashboard/DashboardViewer.tsx | 10 +- frontend/components/dataflow/DataFlowList.tsx | 10 +- .../components/dataflow/DataFlowSidebar.tsx | 4 +- .../components/dataflow/EdgeInfoPanel.tsx | 6 +- .../dataflow/RelationshipListModal.tsx | 16 +- .../components/dataflow/SaveDiagramModal.tsx | 14 +- .../dataflow/SelectedTablesPanel.tsx | 18 +- frontend/components/dataflow/TableNode.tsx | 2 +- .../components/dataflow/TableSelector.tsx | 10 +- .../dataflow/condition/ConditionRenderer.tsx | 18 +- .../dataflow/condition/WebTypeInput.tsx | 2 +- .../connection/ActionConditionsSection.tsx | 12 +- .../connection/ActionFieldMappings.tsx | 8 +- .../connection/ColumnTableSection.tsx | 8 +- .../connection/ConnectionTypeSelector.tsx | 8 +- .../connection/DeleteConditionPanel.tsx | 6 +- .../connection/InsertFieldMappingPanel.tsx | 4 +- .../dataflow/connection/SimpleKeySettings.tsx | 14 +- .../redesigned/DataConnectionDesigner.tsx | 2 +- .../redesigned/LeftPanel/AdvancedSettings.tsx | 6 +- .../LeftPanel/ConnectionTypeSelector.tsx | 4 +- .../redesigned/LeftPanel/LeftPanel.tsx | 4 +- .../redesigned/LeftPanel/MappingInfoPanel.tsx | 14 +- .../ActionConfig/ActionConditionBuilder.tsx | 8 +- .../redesigned/RightPanel/ConnectionStep.tsx | 16 +- .../RightPanel/ControlConditionStep.tsx | 4 +- .../RightPanel/FieldMappingStep.tsx | 20 +- .../RightPanel/MultiActionConfigStep.tsx | 8 +- .../redesigned/RightPanel/RightPanel.tsx | 6 +- .../redesigned/RightPanel/StepProgress.tsx | 4 +- .../redesigned/RightPanel/TableStep.tsx | 20 +- .../RightPanel/VisualMapping/FieldColumn.tsx | 4 +- .../VisualMapping/FieldMappingCanvas.tsx | 2 +- .../external-call/ExternalCallTestPanel.tsx | 2 +- .../external-call/RestApiSettings.tsx | 2 +- frontend/components/layout/AppLayout.tsx | 10 +- frontend/components/layout/ProfileModal.tsx | 6 +- .../components/mail/ConfirmDeleteModal.tsx | 5 +- frontend/components/mail/MailAccountModal.tsx | 12 +- frontend/components/mail/MailAccountTable.tsx | 16 +- frontend/components/mail/MailDesigner.tsx | 6 +- frontend/components/mail/MailDetailModal.tsx | 12 +- frontend/components/mail/MailTemplateCard.tsx | 10 +- .../mail/MailTemplatePreviewModal.tsx | 8 +- .../components/screen/CopyScreenModal.tsx | 2 +- .../components/screen/CreateScreenModal.tsx | 2 +- .../components/screen/DesignerToolbar.tsx | 14 +- frontend/components/screen/EditModal.tsx | 16 +- .../EnhancedInteractiveScreenViewer.tsx | 2 +- .../screen/FileAttachmentDetailModal.tsx | 4 +- frontend/components/screen/GridControls.tsx | 4 +- .../components/screen/GroupingToolbar.tsx | 4 +- .../screen/InteractiveDataTable.tsx | 135 +++--- .../screen/InteractiveScreenViewer.tsx | 8 +- .../screen/InteractiveScreenViewerDynamic.tsx | 18 +- .../components/screen/MenuAssignmentModal.tsx | 10 +- .../screen/OptimizedButtonComponent.tsx | 2 +- .../components/screen/RealtimePreview.tsx | 14 +- .../screen/ResponsiveDesignerContainer.tsx | 2 +- frontend/components/screen/SaveModal.tsx | 305 ++++++++++++++ frontend/components/screen/ScreenDesigner.tsx | 20 +- .../components/screen/ScreenDesigner_old.tsx | 40 +- frontend/components/screen/ScreenList.tsx | 36 +- .../screen/SimpleScreenDesigner.tsx | 2 +- .../components/screen/TemplateManager.tsx | 12 +- frontend/components/screen/WidgetFactory.tsx | 16 +- .../config-panels/ButtonConfigPanel.tsx | 4 +- .../ButtonDataflowConfigPanel.tsx | 12 +- .../screen/config-panels/CodeConfigPanel.tsx | 2 +- .../config-panels/EntityConfigPanel.tsx | 2 +- .../screen/config-panels/FileConfigPanel.tsx | 2 +- .../ImprovedButtonControlConfigPanel.tsx | 12 +- .../screen/filters/AdvancedSearchFilters.tsx | 2 +- .../screen/layout/ColumnComponent.tsx | 2 +- .../screen/layout/ContainerComponent.tsx | 2 +- .../components/screen/layout/RowComponent.tsx | 2 +- .../screen/panels/ComponentsPanel.tsx | 398 +++++++----------- .../screen/panels/DataTableConfigPanel.tsx | 6 +- .../screen/panels/DetailSettingsPanel.tsx | 118 +++--- .../panels/FileComponentConfigPanel.tsx | 8 +- .../components/screen/panels/GridPanel.tsx | 18 +- .../components/screen/panels/LayoutsPanel.tsx | 4 +- .../screen/panels/PropertiesPanel.tsx | 44 +- .../screen/panels/ResolutionPanel.tsx | 12 +- .../components/screen/panels/TablesPanel.tsx | 18 +- .../screen/panels/TemplatesPanel.tsx | 24 +- .../CheckboxTypeConfigPanel.tsx | 2 +- .../webtype-configs/CodeTypeConfigPanel.tsx | 2 +- .../webtype-configs/EntityTypeConfigPanel.tsx | 4 +- .../webtype-configs/FileTypeConfigPanel.tsx | 6 +- .../webtype-configs/RadioTypeConfigPanel.tsx | 6 +- .../webtype-configs/TextTypeConfigPanel.tsx | 6 +- .../components/screen/widgets/FileUpload.tsx | 40 +- .../screen/widgets/types/FileWidget.tsx | 20 +- .../screen/widgets/types/RatingWidget.tsx | 2 +- frontend/components/theme/ThemeSettings.tsx | 4 +- frontend/components/ui/accordion.tsx | 2 +- frontend/constants/auth.ts | 4 +- frontend/lib/api/mail.ts | 55 +-- .../AutoRegisteringComponentRenderer.ts | 2 +- .../AccordionBasicComponent.tsx | 8 +- .../button-primary/ButtonPrimaryComponent.tsx | 55 ++- .../checkbox-basic/CheckboxBasicComponent.tsx | 4 +- .../date-input/DateInputComponent.tsx | 2 +- .../divider-line/DividerLineComponent.tsx | 2 +- .../image-display/ImageDisplayComponent.tsx | 2 +- .../number-input/NumberInputComponent.tsx | 2 +- .../radio-basic/RadioBasicComponent.tsx | 4 +- .../select-basic/SelectBasicComponent.tsx | 2 +- .../slider-basic/SliderBasicComponent.tsx | 4 +- .../table-list/TableListComponent.tsx | 25 +- .../registry/components/table-list/index.ts | 2 +- .../test-input/TestInputComponent.tsx | 2 +- .../text-display/TextDisplayComponent.tsx | 4 +- .../text-display/TextDisplayConfigPanel.tsx | 2 +- .../registry/components/text-display/index.ts | 2 +- .../text-input/TextInputComponent.tsx | 2 +- .../textarea-basic/TextareaBasicComponent.tsx | 2 +- .../toggle-switch/ToggleSwitchComponent.tsx | 4 +- .../layouts/AutoRegisteringLayoutRenderer.tsx | 2 +- .../layouts/accordion/AccordionLayout.tsx | 2 +- frontend/scripts/create-component.js | 6 +- frontend/scripts/unify-colors.sh | 119 ++++++ frontend/types/component.ts | 4 +- 168 files changed, 1545 insertions(+), 1066 deletions(-) create mode 100644 frontend/components/screen/SaveModal.tsx create mode 100755 frontend/scripts/unify-colors.sh diff --git a/backend-node/src/routes/mailAccountFileRoutes.ts b/backend-node/src/routes/mailAccountFileRoutes.ts index cc022cb8..35772d39 100644 --- a/backend-node/src/routes/mailAccountFileRoutes.ts +++ b/backend-node/src/routes/mailAccountFileRoutes.ts @@ -1,8 +1,12 @@ import { Router } from 'express'; import { mailAccountFileController } from '../controllers/mailAccountFileController'; +import { authenticateToken } from '../middleware/authMiddleware'; const router = Router(); +// 모든 메일 계정 라우트에 인증 미들웨어 적용 +router.use(authenticateToken); + router.get('/', (req, res) => mailAccountFileController.getAllAccounts(req, res)); router.get('/:id', (req, res) => mailAccountFileController.getAccountById(req, res)); router.post('/', (req, res) => mailAccountFileController.createAccount(req, res)); diff --git a/backend-node/src/routes/mailReceiveBasicRoutes.ts b/backend-node/src/routes/mailReceiveBasicRoutes.ts index f8d0d670..d21df689 100644 --- a/backend-node/src/routes/mailReceiveBasicRoutes.ts +++ b/backend-node/src/routes/mailReceiveBasicRoutes.ts @@ -4,8 +4,12 @@ import express from 'express'; import { MailReceiveBasicController } from '../controllers/mailReceiveBasicController'; +import { authenticateToken } from '../middleware/authMiddleware'; const router = express.Router(); + +// 모든 메일 수신 라우트에 인증 미들웨어 적용 +router.use(authenticateToken); const controller = new MailReceiveBasicController(); // 메일 목록 조회 diff --git a/backend-node/src/routes/mailSendSimpleRoutes.ts b/backend-node/src/routes/mailSendSimpleRoutes.ts index db56b66d..726a220c 100644 --- a/backend-node/src/routes/mailSendSimpleRoutes.ts +++ b/backend-node/src/routes/mailSendSimpleRoutes.ts @@ -1,8 +1,12 @@ import { Router } from 'express'; import { mailSendSimpleController } from '../controllers/mailSendSimpleController'; +import { authenticateToken } from '../middleware/authMiddleware'; const router = Router(); +// 모든 메일 발송 라우트에 인증 미들웨어 적용 +router.use(authenticateToken); + // POST /api/mail/send/simple - 메일 발송 router.post('/simple', (req, res) => mailSendSimpleController.sendMail(req, res)); diff --git a/backend-node/src/routes/mailTemplateFileRoutes.ts b/backend-node/src/routes/mailTemplateFileRoutes.ts index eb79ed34..a4f81b1b 100644 --- a/backend-node/src/routes/mailTemplateFileRoutes.ts +++ b/backend-node/src/routes/mailTemplateFileRoutes.ts @@ -1,8 +1,12 @@ import { Router } from 'express'; import { mailTemplateFileController } from '../controllers/mailTemplateFileController'; +import { authenticateToken } from '../middleware/authMiddleware'; const router = Router(); +// 모든 메일 템플릿 라우트에 인증 미들웨어 적용 +router.use(authenticateToken); + // 템플릿 CRUD router.get('/', (req, res) => mailTemplateFileController.getAllTemplates(req, res)); router.get('/:id', (req, res) => mailTemplateFileController.getTemplateById(req, res)); diff --git a/frontend/app/(main)/admin/mail/dashboard/page.tsx b/frontend/app/(main)/admin/mail/dashboard/page.tsx index 1fa6a728..f2e737bc 100644 --- a/frontend/app/(main)/admin/mail/dashboard/page.tsx +++ b/frontend/app/(main)/admin/mail/dashboard/page.tsx @@ -14,6 +14,7 @@ import { Calendar, Clock } from "lucide-react"; +import { getMailAccounts, getMailTemplates } from "@/lib/api/mail"; interface DashboardStats { totalAccounts: number; @@ -38,17 +39,15 @@ export default function MailDashboardPage() { const loadStats = async () => { setLoading(true); try { - // 계정 수 - const accountsRes = await fetch('/api/mail/accounts'); - const accountsData = await accountsRes.json(); + // 계정 수 (apiClient를 통해 토큰 포함) + const accounts = await getMailAccounts(); - // 템플릿 수 - const templatesRes = await fetch('/api/mail/templates-file'); - const templatesData = await templatesRes.json(); + // 템플릿 수 (apiClient를 통해 토큰 포함) + const templates = await getMailTemplates(); setStats({ - totalAccounts: accountsData.success ? accountsData.data.length : 0, - totalTemplates: templatesData.success ? templatesData.data.length : 0, + totalAccounts: accounts.length, + totalTemplates: templates.length, sentToday: 0, // TODO: 실제 발송 통계 API 연동 receivedToday: 0, sentThisMonth: 0, diff --git a/frontend/app/(main)/admin/screenMng/page.tsx b/frontend/app/(main)/admin/screenMng/page.tsx index 88dff27f..54da701b 100644 --- a/frontend/app/(main)/admin/screenMng/page.tsx +++ b/frontend/app/(main)/admin/screenMng/page.tsx @@ -83,7 +83,7 @@ export default function ScreenManagementPage() {

{stepConfig.list.title}

-
@@ -121,7 +121,7 @@ export default function ScreenManagementPage() { 이전 단계 -
diff --git a/frontend/app/(main)/admin/validation-demo/page.tsx b/frontend/app/(main)/admin/validation-demo/page.tsx index f84a06f5..2372c4ea 100644 --- a/frontend/app/(main)/admin/validation-demo/page.tsx +++ b/frontend/app/(main)/admin/validation-demo/page.tsx @@ -54,7 +54,7 @@ const TEST_COMPONENTS: ComponentData[] = [ required: true, style: { labelFontSize: "14px", - labelColor: "#3b83f6", + labelColor: "#212121", labelFontWeight: "500", }, } as WidgetComponent, @@ -72,7 +72,7 @@ const TEST_COMPONENTS: ComponentData[] = [ required: true, style: { labelFontSize: "14px", - labelColor: "#3b83f6", + labelColor: "#212121", labelFontWeight: "500", }, } as WidgetComponent, @@ -94,7 +94,7 @@ const TEST_COMPONENTS: ComponentData[] = [ }, style: { labelFontSize: "14px", - labelColor: "#3b83f6", + labelColor: "#212121", labelFontWeight: "500", }, } as WidgetComponent, @@ -112,7 +112,7 @@ const TEST_COMPONENTS: ComponentData[] = [ required: false, style: { labelFontSize: "14px", - labelColor: "#3b83f6", + labelColor: "#212121", labelFontWeight: "500", }, } as WidgetComponent, @@ -130,7 +130,7 @@ const TEST_COMPONENTS: ComponentData[] = [ required: false, style: { labelFontSize: "14px", - labelColor: "#3b83f6", + labelColor: "#212121", labelFontWeight: "500", }, } as WidgetComponent, @@ -152,7 +152,7 @@ const TEST_COMPONENTS: ComponentData[] = [ }, style: { labelFontSize: "14px", - labelColor: "#3b83f6", + labelColor: "#212121", labelFontWeight: "500", }, } as WidgetComponent, diff --git a/frontend/app/(main)/screens/[screenId]/page.tsx b/frontend/app/(main)/screens/[screenId]/page.tsx index 93111ba8..8b186bfa 100644 --- a/frontend/app/(main)/screens/[screenId]/page.tsx +++ b/frontend/app/(main)/screens/[screenId]/page.tsx @@ -148,7 +148,7 @@ export default function ScreenViewPage() { const screenHeight = layout?.screenResolution?.height || 800; return ( -
+
{layout && layout.components.length > 0 ? ( // 캔버스 컴포넌트들을 정확한 해상도로 표시
{layout.components @@ -239,7 +238,7 @@ export default function ScreenViewPage() { const labelText = component.style?.labelText || component.label || ""; const labelStyle = { fontSize: component.style?.labelFontSize || "14px", - color: component.style?.labelColor || "#3b83f6", + color: component.style?.labelColor || "#212121", fontWeight: component.style?.labelFontWeight || "500", backgroundColor: component.style?.labelBackgroundColor || "transparent", padding: component.style?.labelPadding || "0", @@ -379,7 +378,7 @@ export default function ScreenViewPage() { ) : ( // 빈 화면일 때도 깔끔하게 표시
= ({ // 파일 아이콘 가져오기 const getFileIcon = (fileName: string, size: number = 16) => { const extension = fileName.split('.').pop()?.toLowerCase() || ''; - const iconProps = { size, className: "text-gray-600" }; + const iconProps = { size, className: "text-muted-foreground" }; if (['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'].includes(extension)) { - return ; + return ; } if (['mp4', 'avi', 'mov', 'wmv', 'flv', 'webm'].includes(extension)) { return
@@ -320,19 +320,19 @@ export function CodeCategoryFormModal({ className={ isEditing ? updateForm.formState.errors.sortOrder - ? "border-red-500" + ? "border-destructive" : "" : createForm.formState.errors.sortOrder - ? "border-red-500" + ? "border-destructive" : "" } /> {isEditing ? updateForm.formState.errors.sortOrder && ( -

{updateForm.formState.errors.sortOrder.message}

+

{updateForm.formState.errors.sortOrder.message}

) : createForm.formState.errors.sortOrder && ( -

{createForm.formState.errors.sortOrder.message}

+

{createForm.formState.errors.sortOrder.message}

)}
diff --git a/frontend/components/admin/CodeCategoryPanel.tsx b/frontend/components/admin/CodeCategoryPanel.tsx index 96f75d04..645193fc 100644 --- a/frontend/components/admin/CodeCategoryPanel.tsx +++ b/frontend/components/admin/CodeCategoryPanel.tsx @@ -82,7 +82,7 @@ export function CodeCategoryPanel({ selectedCategoryCode, onSelectCategory }: Co return (
-

카테고리를 불러오는 중 오류가 발생했습니다.

+

카테고리를 불러오는 중 오류가 발생했습니다.

@@ -116,7 +116,7 @@ export function CodeCategoryPanel({ selectedCategoryCode, onSelectCategory }: Co onChange={(e) => setShowActiveOnly(e.target.checked)} className="rounded border-gray-300" /> -
diff --git a/frontend/components/admin/CodeDetailPanel.tsx b/frontend/components/admin/CodeDetailPanel.tsx index 680f59f4..3389ad5b 100644 --- a/frontend/components/admin/CodeDetailPanel.tsx +++ b/frontend/components/admin/CodeDetailPanel.tsx @@ -121,7 +121,7 @@ export function CodeDetailPanel({ categoryCode }: CodeDetailPanelProps) { return (
-

코드를 불러오는 중 오류가 발생했습니다.

+

코드를 불러오는 중 오류가 발생했습니다.

@@ -155,7 +155,7 @@ export function CodeDetailPanel({ categoryCode }: CodeDetailPanelProps) { onChange={(e) => setShowActiveOnly(e.target.checked)} className="rounded border-gray-300" /> -
@@ -221,13 +221,13 @@ export function CodeDetailPanel({ categoryCode }: CodeDetailPanelProps) { "transition-colors", activeCode.isActive === "Y" || activeCode.is_active === "Y" ? "bg-green-100 text-green-800" - : "bg-gray-100 text-gray-600", + : "bg-gray-100 text-muted-foreground", )} > {activeCode.isActive === "Y" || activeCode.is_active === "Y" ? "활성" : "비활성"}
-

+

{activeCode.codeValue || activeCode.code_value}

{activeCode.description && ( diff --git a/frontend/components/admin/CodeFormModal.tsx b/frontend/components/admin/CodeFormModal.tsx index 6e915904..26b617a4 100644 --- a/frontend/components/admin/CodeFormModal.tsx +++ b/frontend/components/admin/CodeFormModal.tsx @@ -168,7 +168,7 @@ export function CodeFormModal({ isOpen, onClose, categoryCode, editingCode, code {...form.register("codeValue")} disabled={isLoading || isEditing} // 수정 시에는 비활성화 placeholder="코드값을 입력하세요" - className={(form.formState.errors as any)?.codeValue ? "border-red-500" : ""} + className={(form.formState.errors as any)?.codeValue ? "border-destructive" : ""} onBlur={(e) => { const value = e.target.value.trim(); if (value && !isEditing) { @@ -180,7 +180,7 @@ export function CodeFormModal({ isOpen, onClose, categoryCode, editingCode, code }} /> {(form.formState.errors as any)?.codeValue && ( -

{getErrorMessage((form.formState.errors as any)?.codeValue)}

+

{getErrorMessage((form.formState.errors as any)?.codeValue)}

)} {!isEditing && !(form.formState.errors as any)?.codeValue && ( { const value = e.target.value.trim(); if (value) { @@ -211,7 +211,7 @@ export function CodeFormModal({ isOpen, onClose, categoryCode, editingCode, code }} /> {form.formState.errors.codeName && ( -

{getErrorMessage(form.formState.errors.codeName)}

+

{getErrorMessage(form.formState.errors.codeName)}

)} {!form.formState.errors.codeName && ( { const value = e.target.value.trim(); if (value) { @@ -242,7 +242,7 @@ export function CodeFormModal({ isOpen, onClose, categoryCode, editingCode, code }} /> {form.formState.errors.codeNameEng && ( -

{getErrorMessage(form.formState.errors.codeNameEng)}

+

{getErrorMessage(form.formState.errors.codeNameEng)}

)} {!form.formState.errors.codeNameEng && ( {form.formState.errors.description && ( -

{getErrorMessage(form.formState.errors.description)}

+

{getErrorMessage(form.formState.errors.description)}

)}
@@ -278,10 +278,10 @@ export function CodeFormModal({ isOpen, onClose, categoryCode, editingCode, code {...form.register("sortOrder", { valueAsNumber: true })} disabled={isLoading} min={1} - className={form.formState.errors.sortOrder ? "border-red-500" : ""} + className={form.formState.errors.sortOrder ? "border-destructive" : ""} /> {form.formState.errors.sortOrder && ( -

{getErrorMessage(form.formState.errors.sortOrder)}

+

{getErrorMessage(form.formState.errors.sortOrder)}

)}
diff --git a/frontend/components/admin/ColumnDefinitionTable.tsx b/frontend/components/admin/ColumnDefinitionTable.tsx index c58ed39b..74fd4f33 100644 --- a/frontend/components/admin/ColumnDefinitionTable.tsx +++ b/frontend/components/admin/ColumnDefinitionTable.tsx @@ -188,7 +188,7 @@ export function ColumnDefinitionTable({ columns, onChange, disabled = false }: C const hasRowError = rowErrors.length > 0; return ( - +
{rowErrors.length > 0 && ( -
+
{rowErrors.map((error, i) => (
{error}
))} diff --git a/frontend/components/admin/CreateTableModal.tsx b/frontend/components/admin/CreateTableModal.tsx index 07dae653..7e075ad1 100644 --- a/frontend/components/admin/CreateTableModal.tsx +++ b/frontend/components/admin/CreateTableModal.tsx @@ -248,7 +248,7 @@ export function CreateTableModal({ isOpen, onClose, onSuccess }: CreateTableModa placeholder="예: customer_info" className={tableNameError ? "border-red-300" : ""} /> - {tableNameError &&

{tableNameError}

} + {tableNameError &&

{tableNameError}

}

영문자로 시작, 영문자/숫자/언더스코어만 사용 가능

diff --git a/frontend/components/admin/DDLLogViewer.tsx b/frontend/components/admin/DDLLogViewer.tsx index c978f162..e0184f38 100644 --- a/frontend/components/admin/DDLLogViewer.tsx +++ b/frontend/components/admin/DDLLogViewer.tsx @@ -271,14 +271,14 @@ export function DDLLogViewer({ isOpen, onClose }: DDLLogViewerProps) { {log.success ? ( ) : ( - + )} - + {log.success ? "성공" : "실패"}
{log.error_message && ( -
{log.error_message}
+
{log.error_message}
)} @@ -325,7 +325,7 @@ export function DDLLogViewer({ isOpen, onClose }: DDLLogViewerProps) { 실패 -
{statistics.failedExecutions}
+
{statistics.failedExecutions}
@@ -374,13 +374,13 @@ export function DDLLogViewer({ isOpen, onClose }: DDLLogViewerProps) { {statistics.recentFailures.length > 0 && ( - 최근 실패 로그 + 최근 실패 로그 최근 발생한 DDL 실행 실패 내역입니다.
{statistics.recentFailures.map((failure, index) => ( -
+
{failure.ddl_type} @@ -390,7 +390,7 @@ export function DDLLogViewer({ isOpen, onClose }: DDLLogViewerProps) { {format(new Date(failure.executed_at), "MM-dd HH:mm", { locale: ko })}
-
{failure.error_message}
+
{failure.error_message}
))}
diff --git a/frontend/components/admin/DiskUsageSummary.tsx b/frontend/components/admin/DiskUsageSummary.tsx index 59af8455..096af5f8 100644 --- a/frontend/components/admin/DiskUsageSummary.tsx +++ b/frontend/components/admin/DiskUsageSummary.tsx @@ -120,7 +120,7 @@ export function DiskUsageSummary({ diskUsageInfo, isLoading, onRefresh }: DiskUs
1000 ? "bg-red-500" : summary.totalSizeMB > 500 ? "bg-yellow-500" : "bg-green-500" + summary.totalSizeMB > 1000 ? "bg-destructive/100" : summary.totalSizeMB > 500 ? "bg-yellow-500" : "bg-green-500" }`} style={{ width: `${Math.min((summary.totalSizeMB / 2000) * 100, 100)}%`, diff --git a/frontend/components/admin/ExternalDbConnectionModal.tsx b/frontend/components/admin/ExternalDbConnectionModal.tsx index cb23768f..b9075bc8 100644 --- a/frontend/components/admin/ExternalDbConnectionModal.tsx +++ b/frontend/components/admin/ExternalDbConnectionModal.tsx @@ -450,7 +450,7 @@ export const ExternalDbConnectionModal: React.FC className={`rounded-md border p-3 text-sm ${ testResult.success ? "border-green-200 bg-green-50 text-green-800" - : "border-red-200 bg-red-50 text-red-800" + : "border-destructive/20 bg-destructive/10 text-red-800" }`} >
{testResult.success ? "✅ 연결 성공" : "❌ 연결 실패"}
@@ -469,7 +469,7 @@ export const ExternalDbConnectionModal: React.FC {!testResult.success && testResult.error && (
오류 코드: {testResult.error.code}
- {testResult.error.details &&
{testResult.error.details}
} + {testResult.error.details &&
{testResult.error.details}
}
)}
diff --git a/frontend/components/admin/LayoutFormModal.tsx b/frontend/components/admin/LayoutFormModal.tsx index 972caa7c..b2fe9804 100644 --- a/frontend/components/admin/LayoutFormModal.tsx +++ b/frontend/components/admin/LayoutFormModal.tsx @@ -238,10 +238,10 @@ export const LayoutFormModal: React.FC = ({ open, onOpenCh
1
@@ -249,19 +249,19 @@ export const LayoutFormModal: React.FC = ({ open, onOpenCh
2
템플릿 선택
-
+
3
@@ -304,13 +304,13 @@ export const LayoutFormModal: React.FC = ({ open, onOpenCh setFormData((prev) => ({ ...prev, category: category.id }))} >
- +
{category.name}
{category.description}
@@ -346,7 +346,7 @@ export const LayoutFormModal: React.FC = ({ open, onOpenCh setFormData((prev) => ({ @@ -362,7 +362,7 @@ export const LayoutFormModal: React.FC = ({ open, onOpenCh
{template.name}
{template.zones}개 영역
-
{template.description}
+
{template.description}
예: {template.example}
{template.icon}
@@ -427,7 +427,7 @@ export const LayoutFormModal: React.FC = ({ open, onOpenCh
{generationResult ? ( @@ -479,7 +479,7 @@ export const LayoutFormModal: React.FC = ({ open, onOpenCh
생성될 파일:
-
    +
    • • {formData.name.toLowerCase()}/index.ts
    • • {formData.name.toLowerCase()}/{formData.name}Layout.tsx diff --git a/frontend/components/admin/MenuFormModal.tsx b/frontend/components/admin/MenuFormModal.tsx index 501a0b8d..f8d80592 100644 --- a/frontend/components/admin/MenuFormModal.tsx +++ b/frontend/components/admin/MenuFormModal.tsx @@ -826,10 +826,10 @@ export const MenuFormModal: React.FC = ({ {/* 선택된 화면 정보 표시 */} {selectedScreen && ( -
      +
      {selectedScreen.screenName}
      -
      코드: {selectedScreen.screenCode}
      -
      생성된 URL: {formData.menuUrl}
      +
      코드: {selectedScreen.screenCode}
      +
      생성된 URL: {formData.menuUrl}
      )}
      diff --git a/frontend/components/admin/MenuManagement.tsx b/frontend/components/admin/MenuManagement.tsx index 81c94ae0..ab7ec016 100644 --- a/frontend/components/admin/MenuManagement.tsx +++ b/frontend/components/admin/MenuManagement.tsx @@ -828,7 +828,7 @@ export const MenuManagement: React.FC = () => { handleMenuTypeChange("admin")} > @@ -836,7 +836,7 @@ export const MenuManagement: React.FC = () => {

      {getUITextSync("menu.management.admin")}

      -

      +

      {getUITextSync("menu.management.admin.description")}

      @@ -849,7 +849,7 @@ export const MenuManagement: React.FC = () => { handleMenuTypeChange("user")} > @@ -857,7 +857,7 @@ export const MenuManagement: React.FC = () => {

      {getUITextSync("menu.management.user")}

      -

      +

      {getUITextSync("menu.management.user.description")}

      @@ -997,7 +997,7 @@ export const MenuManagement: React.FC = () => {
      -
      +
      {getUITextSync("menu.list.search.result", { count: getCurrentMenus().length })}
      @@ -1006,7 +1006,7 @@ export const MenuManagement: React.FC = () => {
      -
      +
      {getUITextSync("menu.list.total", { count: getCurrentMenus().length })}
      diff --git a/frontend/components/admin/MenuTable.tsx b/frontend/components/admin/MenuTable.tsx index 40b01fa3..5df95d81 100644 --- a/frontend/components/admin/MenuTable.tsx +++ b/frontend/components/admin/MenuTable.tsx @@ -67,7 +67,7 @@ export const MenuTable: React.FC = ({ const getLevelBadge = (level: number) => { switch (level) { case 0: - return "bg-blue-100 text-blue-800"; + return "bg-primary/20 text-blue-800"; case 1: return "bg-green-100 text-green-800"; case 2: @@ -239,7 +239,7 @@ export const MenuTable: React.FC = ({
      {seq} - +
      = ({ )}
      - +
      {menuUrl ? (
      30 ? "truncate" : "" }`} onClick={() => { diff --git a/frontend/components/admin/MonitoringDashboard.tsx b/frontend/components/admin/MonitoringDashboard.tsx index 43fc1819..500dd4fb 100644 --- a/frontend/components/admin/MonitoringDashboard.tsx +++ b/frontend/components/admin/MonitoringDashboard.tsx @@ -74,8 +74,8 @@ export default function MonitoringDashboard() { const getStatusBadge = (status: string) => { const variants = { completed: "bg-green-100 text-green-800", - failed: "bg-red-100 text-red-800", - running: "bg-blue-100 text-blue-800", + failed: "bg-destructive/20 text-red-800", + running: "bg-primary/20 text-blue-800", pending: "bg-yellow-100 text-yellow-800", cancelled: "bg-gray-100 text-gray-800", }; @@ -129,7 +129,7 @@ export default function MonitoringDashboard() { variant="outline" size="sm" onClick={toggleAutoRefresh} - className={autoRefresh ? "bg-blue-50 text-blue-600" : ""} + className={autoRefresh ? "bg-accent text-primary" : ""} > {autoRefresh ? : } 자동 새로고침 @@ -167,7 +167,7 @@ export default function MonitoringDashboard() {
      🔄
      -
      {monitoring.running_jobs}
      +
      {monitoring.running_jobs}

      현재 실행 중인 작업

      @@ -193,7 +193,7 @@ export default function MonitoringDashboard() {
      -
      {monitoring.failed_jobs_today}
      +
      {monitoring.failed_jobs_today}

      주의가 필요한 작업

      @@ -269,7 +269,7 @@ export default function MonitoringDashboard() { {execution.error_message ? ( - + {execution.error_message} ) : ( diff --git a/frontend/components/admin/MultiLang.tsx b/frontend/components/admin/MultiLang.tsx index 0d9c2a98..abdadcdb 100644 --- a/frontend/components/admin/MultiLang.tsx +++ b/frontend/components/admin/MultiLang.tsx @@ -673,7 +673,7 @@ export default function MultiLangPage() {
      -
      검색 결과: {getFilteredLangKeys().length}건
      +
      검색 결과: {getFilteredLangKeys().length}건
      {/* 테이블 영역 */}
      -
      전체: {getFilteredLangKeys().length}건
      +
      전체: {getFilteredLangKeys().length}건
      = ({ menus (selectedMenu as any).menu_name_kor || "메뉴"} -

      +

      URL: {selectedMenu.menu_url || selectedMenu.MENU_URL || (selectedMenu as any).menu_url || "없음"}

      -

      +

      설명:{" "} {selectedMenu.menu_desc || selectedMenu.MENU_DESC || (selectedMenu as any).menu_desc || "없음"}

      @@ -294,7 +294,7 @@ export const ScreenAssignmentTab: React.FC = ({ menus {screen.isActive === "Y" ? "활성" : "비활성"}
      -

      +

      테이블: {screen.tableName} | 생성일: {screen.createdDate.toLocaleDateString()}

      {screen.description &&

      {screen.description}

      } @@ -306,7 +306,7 @@ export const ScreenAssignmentTab: React.FC = ({ menus setSelectedScreen(screen); setShowUnassignDialog(true); }} - className="text-red-600 hover:text-red-700" + className="text-destructive hover:text-red-700" > @@ -347,7 +347,7 @@ export const ScreenAssignmentTab: React.FC = ({ menus
      setSelectedScreen(screen)} > @@ -357,7 +357,7 @@ export const ScreenAssignmentTab: React.FC = ({ menus {screen.screenCode}
      -

      테이블: {screen.tableName}

      +

      테이블: {screen.tableName}

      )) )} diff --git a/frontend/components/admin/SortableCodeItem.tsx b/frontend/components/admin/SortableCodeItem.tsx index c3731be0..21d456c7 100644 --- a/frontend/components/admin/SortableCodeItem.tsx +++ b/frontend/components/admin/SortableCodeItem.tsx @@ -83,7 +83,7 @@ export function SortableCodeItem({ "cursor-pointer transition-colors", code.isActive === "Y" || code.is_active === "Y" ? "bg-green-100 text-green-800 hover:bg-green-200 hover:text-green-900" - : "bg-gray-100 text-gray-600 hover:bg-gray-200 hover:text-gray-700", + : "bg-gray-100 text-muted-foreground hover:bg-gray-200 hover:text-gray-700", updateCodeMutation.isPending && "cursor-not-allowed opacity-50", )} onClick={(e) => { @@ -100,7 +100,7 @@ export function SortableCodeItem({ {code.isActive === "Y" || code.is_active === "Y" ? "활성" : "비활성"}
      -

      {code.codeValue || code.code_value}

      +

      {code.codeValue || code.code_value}

      {code.description &&

      {code.description}

      }
      diff --git a/frontend/components/admin/UserFormModal.tsx b/frontend/components/admin/UserFormModal.tsx index 0e32a95c..8427fa00 100644 --- a/frontend/components/admin/UserFormModal.tsx +++ b/frontend/components/admin/UserFormModal.tsx @@ -24,9 +24,9 @@ function AlertModal({ isOpen, onClose, title, message, type = "info" }: AlertMod case "success": return "text-green-600"; case "error": - return "text-red-600"; + return "text-destructive"; default: - return "text-blue-600"; + return "text-primary"; } }; @@ -37,7 +37,7 @@ function AlertModal({ isOpen, onClose, title, message, type = "info" }: AlertMod {title}
      -

      {message}

      +

      {message}

      {/* 비밀번호 일치 여부 표시 */} - {showMismatchError &&

      비밀번호가 일치하지 않습니다.

      } + {showMismatchError &&

      비밀번호가 일치하지 않습니다.

      } {isPasswordMatch &&

      비밀번호가 일치합니다.

      }
      diff --git a/frontend/components/admin/UserStatusConfirmDialog.tsx b/frontend/components/admin/UserStatusConfirmDialog.tsx index 72ab1aa3..59a7c1df 100644 --- a/frontend/components/admin/UserStatusConfirmDialog.tsx +++ b/frontend/components/admin/UserStatusConfirmDialog.tsx @@ -33,8 +33,8 @@ export function UserStatusConfirmDialog({ const currentStatusText = USER_STATUS_LABELS[user.status as keyof typeof USER_STATUS_LABELS] || user.status; const newStatusText = USER_STATUS_LABELS[newStatus as keyof typeof USER_STATUS_LABELS] || newStatus; - const currentStatusColor = user.status === "active" ? "text-blue-600" : "text-gray-600"; - const newStatusColor = newStatus === "active" ? "text-blue-600" : "text-gray-600"; + const currentStatusColor = user.status === "active" ? "text-primary" : "text-muted-foreground"; + const newStatusColor = newStatus === "active" ? "text-primary" : "text-muted-foreground"; return ( !open && onCancel()}> @@ -67,7 +67,7 @@ export function UserStatusConfirmDialog({ - diff --git a/frontend/components/admin/dashboard/CanvasElement.tsx b/frontend/components/admin/dashboard/CanvasElement.tsx index d7074aec..f5180379 100644 --- a/frontend/components/admin/dashboard/CanvasElement.tsx +++ b/frontend/components/admin/dashboard/CanvasElement.tsx @@ -227,7 +227,7 @@ export function CanvasElement({ element, isSelected, onUpdate, onRemove, onSelec @@ -89,7 +89,7 @@ export function ElementConfigModal({ element, isOpen, onClose, onSave }: Element className={` px-6 py-3 text-sm font-medium border-b-2 transition-colors ${activeTab === 'query' - ? 'border-blue-500 text-blue-600 bg-blue-50' + ? 'border-primary text-primary bg-accent' : 'border-transparent text-gray-500 hover:text-gray-700'} `} > @@ -100,7 +100,7 @@ export function ElementConfigModal({ element, isOpen, onClose, onSave }: Element className={` px-6 py-3 text-sm font-medium border-b-2 transition-colors ${activeTab === 'chart' - ? 'border-blue-500 text-blue-600 bg-blue-50' + ? 'border-primary text-primary bg-accent' : 'border-transparent text-gray-500 hover:text-gray-700'} `} > @@ -147,7 +147,7 @@ export function ElementConfigModal({ element, isOpen, onClose, onSave }: Element
      @@ -155,7 +155,7 @@ export function ElementConfigModal({ element, isOpen, onClose, onSave }: Element onClick={handleSave} disabled={!dataSource.query || (!chartConfig.xAxis || !chartConfig.yAxis)} className=" - px-4 py-2 bg-blue-500 text-white rounded-lg + px-4 py-2 bg-accent0 text-white rounded-lg hover:bg-blue-600 disabled:bg-gray-300 disabled:cursor-not-allowed " > diff --git a/frontend/components/admin/dashboard/QueryEditor.tsx b/frontend/components/admin/dashboard/QueryEditor.tsx index 671024cd..5aa70a80 100644 --- a/frontend/components/admin/dashboard/QueryEditor.tsx +++ b/frontend/components/admin/dashboard/QueryEditor.tsx @@ -153,7 +153,7 @@ ORDER BY Q4 DESC;` onClick={executeQuery} disabled={isExecuting || !query.trim()} className=" - px-3 py-1 bg-blue-500 text-white rounded text-sm + px-3 py-1 bg-accent0 text-white rounded text-sm hover:bg-blue-600 disabled:bg-gray-300 disabled:cursor-not-allowed flex items-center gap-1 " @@ -172,10 +172,10 @@ ORDER BY Q4 DESC;` {/* 샘플 쿼리 버튼들 */}
      - 샘플 쿼리: + 샘플 쿼리: @@ -224,7 +224,7 @@ ORDER BY Q4 DESC;` {/* 새로고침 간격 설정 */}
      - + { @@ -277,7 +277,7 @@ export const ActionFieldMappings: React.FC = ({ updateFieldMapping(mappingIndex, "sourceTable", ""); updateFieldMapping(mappingIndex, "sourceField", ""); }} - className="ml-1 flex h-4 w-4 items-center justify-center rounded-full text-gray-400 hover:bg-gray-200 hover:text-gray-600" + className="ml-1 flex h-4 w-4 items-center justify-center rounded-full text-gray-400 hover:bg-gray-200 hover:text-muted-foreground" title="소스 테이블 지우기" > × @@ -390,7 +390,7 @@ export const ActionFieldMappings: React.FC = ({ {/* 필드 매핑이 없을 때 안내 메시지 */} {action.fieldMappings.length === 0 && ( -
      +
      ⚠️
      diff --git a/frontend/components/dataflow/connection/ColumnTableSection.tsx b/frontend/components/dataflow/connection/ColumnTableSection.tsx index b34b768c..631403b0 100644 --- a/frontend/components/dataflow/connection/ColumnTableSection.tsx +++ b/frontend/components/dataflow/connection/ColumnTableSection.tsx @@ -190,7 +190,7 @@ export const ColumnTableSection: React.FC = ({ : isMapped ? "bg-gray-100 text-gray-700" : oppositeSelectedColumn && !isTypeCompatible - ? "cursor-not-allowed bg-red-50 text-red-400 opacity-60" + ? "cursor-not-allowed bg-destructive/10 text-red-400 opacity-60" : isClickable ? "cursor-pointer hover:bg-gray-50" : "cursor-not-allowed bg-gray-100 text-gray-400" @@ -250,7 +250,7 @@ export const ColumnTableSection: React.FC = ({ : hasDefaultValue ? "bg-gray-100" : oppositeSelectedColumn && !isTypeCompatible - ? "bg-red-50 opacity-60" + ? "bg-destructive/10 opacity-60" : "bg-white" }`} > @@ -292,7 +292,7 @@ export const ColumnTableSection: React.FC = ({ {isMapped && (
      - ← {mapping.fromColumnName} + ← {mapping.fromColumnName}
      {/* 하단 통계 */} -
      +
      {isFromTable ? "매핑됨" : "설정됨"}: {mappedCount}/{columns.length} diff --git a/frontend/components/dataflow/connection/ConnectionTypeSelector.tsx b/frontend/components/dataflow/connection/ConnectionTypeSelector.tsx index 1959582a..b4218bde 100644 --- a/frontend/components/dataflow/connection/ConnectionTypeSelector.tsx +++ b/frontend/components/dataflow/connection/ConnectionTypeSelector.tsx @@ -18,14 +18,14 @@ export const ConnectionTypeSelector: React.FC = ({
      onConfigChange({ ...config, connectionType: "simple-key" })} >
      단순 키값 연결
      -
      중계 테이블 생성
      +
      중계 테이블 생성
      = ({ >
      데이터 저장
      -
      필드 매핑 저장
      +
      필드 매핑 저장
      = ({ >
      외부 호출
      -
      API/이메일 호출
      +
      API/이메일 호출
      diff --git a/frontend/components/dataflow/connection/DeleteConditionPanel.tsx b/frontend/components/dataflow/connection/DeleteConditionPanel.tsx index 7e60c9f9..d1468d64 100644 --- a/frontend/components/dataflow/connection/DeleteConditionPanel.tsx +++ b/frontend/components/dataflow/connection/DeleteConditionPanel.tsx @@ -299,7 +299,7 @@ export const DeleteConditionPanel: React.FC = ({ = - != + != > < @@ -308,11 +308,11 @@ export const DeleteConditionPanel: React.FC = ({ LIKE IN - NOT IN + NOT IN EXISTS - NOT EXISTS + NOT EXISTS diff --git a/frontend/components/dataflow/connection/InsertFieldMappingPanel.tsx b/frontend/components/dataflow/connection/InsertFieldMappingPanel.tsx index e55e23a6..b5b33362 100644 --- a/frontend/components/dataflow/connection/InsertFieldMappingPanel.tsx +++ b/frontend/components/dataflow/connection/InsertFieldMappingPanel.tsx @@ -446,9 +446,9 @@ export const InsertFieldMappingPanel: React.FC = (
      매핑 진행 상황
      -
      +
      총 {toTableColumns.length}개 컬럼 중{" "} - + {columnMappings.filter((m) => m.fromColumnName || (m.defaultValue && m.defaultValue.trim())).length} 개 {" "} diff --git a/frontend/components/dataflow/connection/SimpleKeySettings.tsx b/frontend/components/dataflow/connection/SimpleKeySettings.tsx index 439d9e46..018fbb06 100644 --- a/frontend/components/dataflow/connection/SimpleKeySettings.tsx +++ b/frontend/components/dataflow/connection/SimpleKeySettings.tsx @@ -44,7 +44,7 @@ export const SimpleKeySettings: React.FC = ({ {/* 현재 선택된 테이블 표시 */}
      - +
      {availableTables.find((t) => t.tableName === selectedFromTable)?.displayName || selectedFromTable} @@ -54,7 +54,7 @@ export const SimpleKeySettings: React.FC = ({
      - +
      {availableTables.find((t) => t.tableName === selectedToTable)?.displayName || selectedToTable} @@ -67,7 +67,7 @@ export const SimpleKeySettings: React.FC = ({ {/* 컬럼 선택 */}
      - +
      {fromTableColumns.map((column) => (
      - +
      {toTableColumns.map((column) => (