From b8e8328b1ffffb80bf4ebb776a4a24e5680fc5bc Mon Sep 17 00:00:00 2001 From: dujinkim Date: Fri, 28 Mar 2025 00:42:08 +0000 Subject: 테이블 칼럼 리사이즈 및 핀 충돌 해결 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + components/data-table/data-table-column-header.tsx | 15 +- components/data-table/data-table-pin-right.tsx | 173 +- components/data-table/data-table.tsx | 30 +- components/documents/view-document-dialog.tsx | 244 +- components/form-data/form-data-table.tsx | 4 +- config/poColumnsConfig.ts | 56 +- db/migrations/0094_brave_sue_storm.sql | 55 + db/migrations/0094_fresh_blur.sql | 783 +++ db/migrations/0095_abnormal_virginia_dare.sql | 55 + db/migrations/0095_odd_slayback.sql | 55 + db/migrations/0096_far_lord_tyger.sql | 2 - db/migrations/0097_worried_cobalt_man.sql | 10 - db/migrations/0098_cooing_reptil.sql | 5 - db/migrations/0099_parallel_ink.sql | 2 - db/migrations/0100_abandoned_moonstone.sql | 4 - db/migrations/0101_past_killraven.sql | 5 - db/migrations/0102_melodic_blob.sql | 1 - db/migrations/0103_huge_wallflower.sql | 37 - db/migrations/meta/0000_snapshot.json | 360 -- db/migrations/meta/0001_snapshot.json | 499 -- db/migrations/meta/0002_snapshot.json | 506 -- db/migrations/meta/0003_snapshot.json | 513 -- db/migrations/meta/0004_snapshot.json | 533 --- db/migrations/meta/0005_snapshot.json | 592 --- db/migrations/meta/0006_snapshot.json | 541 --- db/migrations/meta/0007_snapshot.json | 772 --- db/migrations/meta/0008_snapshot.json | 772 --- db/migrations/meta/0009_snapshot.json | 778 --- db/migrations/meta/0010_snapshot.json | 1442 ------ db/migrations/meta/0011_snapshot.json | 1456 ------ db/migrations/meta/0012_snapshot.json | 1456 ------ db/migrations/meta/0013_snapshot.json | 1462 ------ db/migrations/meta/0014_snapshot.json | 1527 ------ db/migrations/meta/0015_snapshot.json | 1535 ------ db/migrations/meta/0016_snapshot.json | 1554 ------ db/migrations/meta/0017_snapshot.json | 1561 ------ db/migrations/meta/0018_snapshot.json | 1577 ------- db/migrations/meta/0019_snapshot.json | 1585 ------- db/migrations/meta/0020_snapshot.json | 1585 ------- db/migrations/meta/0021_snapshot.json | 1591 ------- db/migrations/meta/0022_snapshot.json | 1642 ------- db/migrations/meta/0023_snapshot.json | 2046 -------- db/migrations/meta/0024_snapshot.json | 2062 -------- db/migrations/meta/0025_snapshot.json | 2055 -------- db/migrations/meta/0026_snapshot.json | 2074 -------- db/migrations/meta/0027_snapshot.json | 2080 -------- db/migrations/meta/0028_snapshot.json | 2100 --------- db/migrations/meta/0029_snapshot.json | 2119 --------- db/migrations/meta/0030_snapshot.json | 2215 --------- db/migrations/meta/0031_snapshot.json | 2221 --------- db/migrations/meta/0032_snapshot.json | 2227 --------- db/migrations/meta/0033_snapshot.json | 2247 --------- db/migrations/meta/0034_snapshot.json | 2394 ---------- db/migrations/meta/0035_snapshot.json | 2388 ---------- db/migrations/meta/0036_snapshot.json | 2444 ---------- db/migrations/meta/0037_snapshot.json | 2501 ---------- db/migrations/meta/0038_snapshot.json | 2501 ---------- db/migrations/meta/0039_snapshot.json | 2529 ---------- db/migrations/meta/0040_snapshot.json | 2557 ---------- db/migrations/meta/0041_snapshot.json | 2566 ---------- db/migrations/meta/0042_snapshot.json | 2640 ----------- db/migrations/meta/0043_snapshot.json | 2620 ----------- db/migrations/meta/0044_snapshot.json | 2640 ----------- db/migrations/meta/0045_snapshot.json | 2651 ----------- db/migrations/meta/0046_snapshot.json | 2639 ----------- db/migrations/meta/0047_snapshot.json | 2892 ------------ db/migrations/meta/0048_snapshot.json | 2971 ------------ db/migrations/meta/0049_snapshot.json | 2979 ------------ db/migrations/meta/0050_snapshot.json | 3055 ------------ db/migrations/meta/0051_snapshot.json | 3086 ------------ db/migrations/meta/0052_snapshot.json | 3100 ------------ db/migrations/meta/0053_snapshot.json | 3107 ------------ db/migrations/meta/0054_snapshot.json | 3193 ------------- db/migrations/meta/0055_snapshot.json | 3145 ------------- db/migrations/meta/0056_snapshot.json | 3214 ------------- db/migrations/meta/0057_snapshot.json | 3214 ------------- db/migrations/meta/0058_snapshot.json | 3236 ------------- db/migrations/meta/0059_snapshot.json | 3264 ------------- db/migrations/meta/0060_snapshot.json | 3461 -------------- db/migrations/meta/0061_snapshot.json | 3475 -------------- db/migrations/meta/0062_snapshot.json | 3544 -------------- db/migrations/meta/0063_snapshot.json | 3538 -------------- db/migrations/meta/0064_snapshot.json | 3551 -------------- db/migrations/meta/0065_snapshot.json | 3609 -------------- db/migrations/meta/0066_snapshot.json | 3609 -------------- db/migrations/meta/0067_snapshot.json | 3656 -------------- db/migrations/meta/0068_snapshot.json | 3656 -------------- db/migrations/meta/0069_snapshot.json | 3656 -------------- db/migrations/meta/0070_snapshot.json | 3656 -------------- db/migrations/meta/0071_snapshot.json | 3656 -------------- db/migrations/meta/0072_snapshot.json | 3643 -------------- db/migrations/meta/0073_snapshot.json | 3676 --------------- db/migrations/meta/0074_snapshot.json | 3676 --------------- db/migrations/meta/0075_snapshot.json | 3978 ---------------- db/migrations/meta/0076_snapshot.json | 4167 ---------------- db/migrations/meta/0077_snapshot.json | 4175 ---------------- db/migrations/meta/0078_snapshot.json | 4175 ---------------- db/migrations/meta/0079_snapshot.json | 4175 ---------------- db/migrations/meta/0080_snapshot.json | 4175 ---------------- db/migrations/meta/0081_snapshot.json | 4175 ---------------- db/migrations/meta/0082_snapshot.json | 4453 ------------------ db/migrations/meta/0083_snapshot.json | 4453 ------------------ db/migrations/meta/0084_snapshot.json | 4453 ------------------ db/migrations/meta/0085_snapshot.json | 4453 ------------------ db/migrations/meta/0086_snapshot.json | 4557 ------------------ db/migrations/meta/0087_snapshot.json | 4971 -------------------- db/migrations/meta/0088_snapshot.json | 4743 ------------------- db/migrations/meta/0089_snapshot.json | 4743 ------------------- db/migrations/meta/0090_snapshot.json | 4627 ------------------ db/migrations/meta/0091_snapshot.json | 4627 ------------------ db/migrations/meta/0092_snapshot.json | 4627 ------------------ db/migrations/meta/0093_snapshot.json | 4635 ------------------ db/migrations/meta/0094_snapshot.json | 122 +- db/migrations/meta/0095_snapshot.json | 109 +- db/migrations/meta/0096_snapshot.json | 4673 ------------------ db/migrations/meta/0097_snapshot.json | 4743 ------------------- db/migrations/meta/0098_snapshot.json | 4743 ------------------- db/migrations/meta/0099_snapshot.json | 4755 ------------------- db/migrations/meta/0100_snapshot.json | 4757 ------------------- db/migrations/meta/0101_snapshot.json | 4757 ------------------- db/migrations/meta/0102_snapshot.json | 4757 ------------------- db/migrations/meta/0103_snapshot.json | 4757 ------------------- db/migrations/meta/_journal.json | 16 +- db/schema/contract.ts | 244 +- lib/po/service.ts | 4 + lib/po/table/esign-dialog.tsx | 112 + lib/po/table/item-dialog.tsx | 173 + lib/po/table/po-table-columns.tsx | 300 +- lib/po/table/po-table-toolbar-actions.tsx | 4 +- lib/po/table/po-table.tsx | 125 +- lib/po/table/sign-request-dialog.tsx | 359 +- package-lock.json | 1 + types/table.d.ts | 2 +- 134 files changed, 2326 insertions(+), 299959 deletions(-) create mode 100644 db/migrations/0094_brave_sue_storm.sql create mode 100644 db/migrations/0094_fresh_blur.sql create mode 100644 db/migrations/0095_abnormal_virginia_dare.sql create mode 100644 db/migrations/0095_odd_slayback.sql delete mode 100644 db/migrations/0096_far_lord_tyger.sql delete mode 100644 db/migrations/0097_worried_cobalt_man.sql delete mode 100644 db/migrations/0098_cooing_reptil.sql delete mode 100644 db/migrations/0099_parallel_ink.sql delete mode 100644 db/migrations/0100_abandoned_moonstone.sql delete mode 100644 db/migrations/0101_past_killraven.sql delete mode 100644 db/migrations/0102_melodic_blob.sql delete mode 100644 db/migrations/0103_huge_wallflower.sql delete mode 100644 db/migrations/meta/0000_snapshot.json delete mode 100644 db/migrations/meta/0001_snapshot.json delete mode 100644 db/migrations/meta/0002_snapshot.json delete mode 100644 db/migrations/meta/0003_snapshot.json delete mode 100644 db/migrations/meta/0004_snapshot.json delete mode 100644 db/migrations/meta/0005_snapshot.json delete mode 100644 db/migrations/meta/0006_snapshot.json delete mode 100644 db/migrations/meta/0007_snapshot.json delete mode 100644 db/migrations/meta/0008_snapshot.json delete mode 100644 db/migrations/meta/0009_snapshot.json delete mode 100644 db/migrations/meta/0010_snapshot.json delete mode 100644 db/migrations/meta/0011_snapshot.json delete mode 100644 db/migrations/meta/0012_snapshot.json delete mode 100644 db/migrations/meta/0013_snapshot.json delete mode 100644 db/migrations/meta/0014_snapshot.json delete mode 100644 db/migrations/meta/0015_snapshot.json delete mode 100644 db/migrations/meta/0016_snapshot.json delete mode 100644 db/migrations/meta/0017_snapshot.json delete mode 100644 db/migrations/meta/0018_snapshot.json delete mode 100644 db/migrations/meta/0019_snapshot.json delete mode 100644 db/migrations/meta/0020_snapshot.json delete mode 100644 db/migrations/meta/0021_snapshot.json delete mode 100644 db/migrations/meta/0022_snapshot.json delete mode 100644 db/migrations/meta/0023_snapshot.json delete mode 100644 db/migrations/meta/0024_snapshot.json delete mode 100644 db/migrations/meta/0025_snapshot.json delete mode 100644 db/migrations/meta/0026_snapshot.json delete mode 100644 db/migrations/meta/0027_snapshot.json delete mode 100644 db/migrations/meta/0028_snapshot.json delete mode 100644 db/migrations/meta/0029_snapshot.json delete mode 100644 db/migrations/meta/0030_snapshot.json delete mode 100644 db/migrations/meta/0031_snapshot.json delete mode 100644 db/migrations/meta/0032_snapshot.json delete mode 100644 db/migrations/meta/0033_snapshot.json delete mode 100644 db/migrations/meta/0034_snapshot.json delete mode 100644 db/migrations/meta/0035_snapshot.json delete mode 100644 db/migrations/meta/0036_snapshot.json delete mode 100644 db/migrations/meta/0037_snapshot.json delete mode 100644 db/migrations/meta/0038_snapshot.json delete mode 100644 db/migrations/meta/0039_snapshot.json delete mode 100644 db/migrations/meta/0040_snapshot.json delete mode 100644 db/migrations/meta/0041_snapshot.json delete mode 100644 db/migrations/meta/0042_snapshot.json delete mode 100644 db/migrations/meta/0043_snapshot.json delete mode 100644 db/migrations/meta/0044_snapshot.json delete mode 100644 db/migrations/meta/0045_snapshot.json delete mode 100644 db/migrations/meta/0046_snapshot.json delete mode 100644 db/migrations/meta/0047_snapshot.json delete mode 100644 db/migrations/meta/0048_snapshot.json delete mode 100644 db/migrations/meta/0049_snapshot.json delete mode 100644 db/migrations/meta/0050_snapshot.json delete mode 100644 db/migrations/meta/0051_snapshot.json delete mode 100644 db/migrations/meta/0052_snapshot.json delete mode 100644 db/migrations/meta/0053_snapshot.json delete mode 100644 db/migrations/meta/0054_snapshot.json delete mode 100644 db/migrations/meta/0055_snapshot.json delete mode 100644 db/migrations/meta/0056_snapshot.json delete mode 100644 db/migrations/meta/0057_snapshot.json delete mode 100644 db/migrations/meta/0058_snapshot.json delete mode 100644 db/migrations/meta/0059_snapshot.json delete mode 100644 db/migrations/meta/0060_snapshot.json delete mode 100644 db/migrations/meta/0061_snapshot.json delete mode 100644 db/migrations/meta/0062_snapshot.json delete mode 100644 db/migrations/meta/0063_snapshot.json delete mode 100644 db/migrations/meta/0064_snapshot.json delete mode 100644 db/migrations/meta/0065_snapshot.json delete mode 100644 db/migrations/meta/0066_snapshot.json delete mode 100644 db/migrations/meta/0067_snapshot.json delete mode 100644 db/migrations/meta/0068_snapshot.json delete mode 100644 db/migrations/meta/0069_snapshot.json delete mode 100644 db/migrations/meta/0070_snapshot.json delete mode 100644 db/migrations/meta/0071_snapshot.json delete mode 100644 db/migrations/meta/0072_snapshot.json delete mode 100644 db/migrations/meta/0073_snapshot.json delete mode 100644 db/migrations/meta/0074_snapshot.json delete mode 100644 db/migrations/meta/0075_snapshot.json delete mode 100644 db/migrations/meta/0076_snapshot.json delete mode 100644 db/migrations/meta/0077_snapshot.json delete mode 100644 db/migrations/meta/0078_snapshot.json delete mode 100644 db/migrations/meta/0079_snapshot.json delete mode 100644 db/migrations/meta/0080_snapshot.json delete mode 100644 db/migrations/meta/0081_snapshot.json delete mode 100644 db/migrations/meta/0082_snapshot.json delete mode 100644 db/migrations/meta/0083_snapshot.json delete mode 100644 db/migrations/meta/0084_snapshot.json delete mode 100644 db/migrations/meta/0085_snapshot.json delete mode 100644 db/migrations/meta/0086_snapshot.json delete mode 100644 db/migrations/meta/0087_snapshot.json delete mode 100644 db/migrations/meta/0088_snapshot.json delete mode 100644 db/migrations/meta/0089_snapshot.json delete mode 100644 db/migrations/meta/0090_snapshot.json delete mode 100644 db/migrations/meta/0091_snapshot.json delete mode 100644 db/migrations/meta/0092_snapshot.json delete mode 100644 db/migrations/meta/0093_snapshot.json delete mode 100644 db/migrations/meta/0096_snapshot.json delete mode 100644 db/migrations/meta/0097_snapshot.json delete mode 100644 db/migrations/meta/0098_snapshot.json delete mode 100644 db/migrations/meta/0099_snapshot.json delete mode 100644 db/migrations/meta/0100_snapshot.json delete mode 100644 db/migrations/meta/0101_snapshot.json delete mode 100644 db/migrations/meta/0102_snapshot.json delete mode 100644 db/migrations/meta/0103_snapshot.json create mode 100644 lib/po/table/esign-dialog.tsx create mode 100644 lib/po/table/item-dialog.tsx diff --git a/.gitignore b/.gitignore index 4aa665ad..de61ac2e 100644 --- a/.gitignore +++ b/.gitignore @@ -52,6 +52,7 @@ next-env.d.ts /public/vendors /public/profiles /public/vendorFormData +/tmp # 직접 참조가 불가능해 복사가 필요했던 라이브러리 (pdftrone) # node_modules/@pdftron/public 경로에서 core 및 ui 경로를 복사해 사용 diff --git a/components/data-table/data-table-column-header.tsx b/components/data-table/data-table-column-header.tsx index aa0c754b..795531c8 100644 --- a/components/data-table/data-table-column-header.tsx +++ b/components/data-table/data-table-column-header.tsx @@ -24,15 +24,18 @@ export function DataTableColumnHeader({ className, }: DataTableColumnHeaderProps) { if (!column.getCanSort() && !column.getCanHide()) { - return
{title}
+ return
{title}
} const ascValue = `${column.id}-asc` const descValue = `${column.id}-desc` const hideValue = `${column.id}-hide` + // 현재 컬럼 pinned 상태 + const isPinned = column.getIsPinned(); + return ( -
+
) -} +} \ No newline at end of file diff --git a/components/data-table/data-table-pin-right.tsx b/components/data-table/data-table-pin-right.tsx index 051dd985..3ed42402 100644 --- a/components/data-table/data-table-pin-right.tsx +++ b/components/data-table/data-table-pin-right.tsx @@ -1,7 +1,7 @@ "use client" import * as React from "react" -import { type Table } from "@tanstack/react-table" +import { type Column, type Table } from "@tanstack/react-table" import { Check, ChevronsUpDown, MoveRight } from "lucide-react" import { cn, toSentenceCase } from "@/lib/utils" @@ -13,6 +13,7 @@ import { CommandInput, CommandItem, CommandList, + CommandSeparator, } from "@/components/ui/command" import { Popover, @@ -21,12 +22,99 @@ import { } from "@/components/ui/popover" /** - * “Pin Right” Popover. Similar to PinLeftButton, but pins columns to "right". + * Helper function to check if a column is a parent column (has subcolumns) + */ +function isParentColumn(column: Column): boolean { + return column.columns && column.columns.length > 0 +} + +/** + * Helper function to pin all subcolumns of a parent column + */ +function pinSubColumns( + column: Column, + pinType: false | "left" | "right" +): void { + // If this is a parent column, pin all its subcolumns + if (isParentColumn(column)) { + column.columns.forEach((subColumn) => { + // Recursively handle nested columns + pinSubColumns(subColumn, pinType) + }) + } else { + // For leaf columns, apply the pin if possible + if (column.getCanPin?.()) { + column.pin?.(pinType) + } + } +} + +/** + * Checks if all subcolumns of a parent column are pinned to the specified side + */ +function areAllSubColumnsPinned( + column: Column, + pinType: "left" | "right" +): boolean { + if (isParentColumn(column)) { + // Check if all subcolumns are pinned + return column.columns.every((subColumn) => + areAllSubColumnsPinned(subColumn, pinType) + ) + } else { + // For leaf columns, check if it's pinned to the specified side + return column.getIsPinned?.() === pinType + } +} + +/** + * "Pin Right" Popover. Supports pinning both individual columns and header groups. */ export function PinRightButton({ table }: { table: Table }) { const [open, setOpen] = React.useState(false) const triggerRef = React.useRef(null) + // Get all columns that can be pinned, including parent columns + const pinnableColumns = React.useMemo(() => { + return table.getAllColumns().filter((column) => { + // If it's a leaf column, check if it can be pinned + if (!isParentColumn(column)) { + return column.getCanPin?.() + } + + // If it's a parent column, check if at least one subcolumn can be pinned + return column.columns.some((subCol) => { + if (isParentColumn(subCol)) { + // Recursively check nested columns + return subCol.columns.some(c => c.getCanPin?.()) + } + return subCol.getCanPin?.() + }) + }) + }, [table]) + + // Handle column pinning + const handleColumnPin = React.useCallback((column: Column) => { + // For parent columns, pin/unpin all subcolumns + if (isParentColumn(column)) { + const allPinned = areAllSubColumnsPinned(column, "right") + pinSubColumns(column, allPinned ? false : "right") + } else { + // For leaf columns, toggle pin state + const isPinned = column.getIsPinned?.() === "right" + column.pin?.(isPinned ? false : "right") + } + }, []) + + // Check if a column or its subcolumns are pinned right + const isColumnPinned = React.useCallback((column: Column): boolean => { + if (isParentColumn(column)) { + return areAllSubColumnsPinned(column, "right") + } else { + return column.getIsPinned?.() === "right" + } + }, []) + return ( @@ -37,17 +125,17 @@ export function PinRightButton({ table }: { table: Table }) { className="h-8 gap-2" > - + Right - + triggerRef.current?.focus()} > @@ -55,30 +143,57 @@ export function PinRightButton({ table }: { table: Table }) { No columns found. - {table - .getAllLeafColumns() - .filter((col) => col.getCanPin?.()) - .map((column) => { - const pinned = column.getIsPinned?.() - return ( - { - column.pin?.(pinned === "right" ? false : "right") - }} - > - - {toSentenceCase(column.id)} - - - - ) - })} + {/* Header Columns (Parent Columns) */} + {pinnableColumns + .filter(isParentColumn) + .map((column) => ( + { + handleColumnPin(column) + }} + className="font-medium" + > + + {column.id === "Basic Info" || column.id === "Metadata" + ? column.id // Use column ID directly for common groups + : toSentenceCase(column.id)} + + + + ))} + + {pinnableColumns.some(isParentColumn) && + pinnableColumns.some(col => !isParentColumn(col)) && ( + + )} + + {/* Leaf Columns (individual columns) */} + {pinnableColumns + .filter(col => !isParentColumn(col)) + .map((column) => ( + { + handleColumnPin(column) + }} + > + + {toSentenceCase(column.id)} + + + + ))} diff --git a/components/data-table/data-table.tsx b/components/data-table/data-table.tsx index 3d01994a..b1027cc0 100644 --- a/components/data-table/data-table.tsx +++ b/components/data-table/data-table.tsx @@ -41,8 +41,8 @@ export function DataTable({ return (
{children} -
- +
+
{/* ------------------------------- Table Header → 그룹핑된 컬럼의 헤더는 숨김 처리 @@ -60,24 +60,26 @@ export function DataTable({ - {header.isPlaceholder - ? null - : flexRender( +
+ {header.isPlaceholder + ? null + : flexRender( header.column.columnDef.header, header.getContext() )} - - {/* 리사이즈 핸들 - 별도의 컴포넌트로 분리 */} - {header.column.getCanResize() && ( - - )} + + {/* 리사이즈 핸들 - 별도의 컴포넌트로 분리 */} + {header.column.getCanResize() && ( + + )} +
) })} @@ -115,7 +117,7 @@ export function DataTable({ data-state={row.getIsExpanded() && "expanded"} > {/* 그룹 헤더는 한 줄에 합쳐서 보여주고, 토글 버튼 + 그룹 라벨 + 값 표기 */} - + {/* 확장/축소 버튼 (아이콘 중앙 정렬 + Indent) */} {row.getCanExpand() && ( - {open && ( - - )} - - ); -} - -const DocumentViewer: React.FC<{ - open: boolean; - setOpen: React.Dispatch>; - versions: Version[]; -}> = ({ open, setOpen, versions }) => { - const [instance, setInstance] = React.useState( - null - ); - const [viwerLoading, setViewerLoading] = React.useState(true); - const [fileSetLoading, setFileSetLoading] = React.useState(true); -======= "use client" import * as React from "react" @@ -85,7 +8,14 @@ import { } from "@/components/ui/dialog" import { Building2, FileIcon, Loader2 } from "lucide-react" import { Button } from "@/components/ui/button" -import fs from "fs" + +interface Attachment { + id: number; + fileName: string; + filePath: string; + fileType?: string; +} + interface Version { id: number @@ -135,34 +65,22 @@ function DocumentViewer({open, setOpen, versions}){ const [instance, setInstance] = React.useState(null) const [viwerLoading, setViewerLoading] = React.useState(true) const [fileSetLoading, setFileSetLoading] = React.useState(true) ->>>>>>> cac978d5c77e9b30165e4fbe6930eeac9862204d const viewer = React.useRef(null); const initialized = React.useRef(false); const isCancelled = React.useRef(false); // 초기화 중단용 flag const cleanupHtmlStyle = () => { const htmlElement = document.documentElement; -<<<<<<< HEAD - - // 기존 style 속성 가져오기 - const originalStyle = htmlElement.getAttribute("style") || ""; - -======= // 기존 style 속성 가져오기 const originalStyle = htmlElement.getAttribute("style") || ""; ->>>>>>> cac978d5c77e9b30165e4fbe6930eeac9862204d // "color-scheme: light" 또는 "color-scheme: dark" 찾기 const colorSchemeStyle = originalStyle .split(";") .map((s) => s.trim()) .find((s) => s.startsWith("color-scheme:")); -<<<<<<< HEAD - -======= ->>>>>>> cac978d5c77e9b30165e4fbe6930eeac9862204d // 새로운 스타일 적용 (color-scheme만 유지) if (colorSchemeStyle) { htmlElement.setAttribute("style", colorSchemeStyle + ";"); @@ -170,46 +88,13 @@ function DocumentViewer({open, setOpen, versions}){ htmlElement.removeAttribute("style"); // color-scheme도 없으면 style 속성 자체 삭제 } -<<<<<<< HEAD - console.log("html style 삭제"); -======= console.log("html style 삭제") ->>>>>>> cac978d5c77e9b30165e4fbe6930eeac9862204d }; React.useEffect(() => { if (open && !initialized.current) { initialized.current = true; isCancelled.current = false; // 다시 열릴 때는 false로 리셋 -<<<<<<< HEAD - - requestAnimationFrame(() => { - if (viewer.current) { - import("@pdftron/webviewer").then(({ default: WebViewer }) => { - console.log(isCancelled.current); - if (isCancelled.current) { - console.log("📛 WebViewer 초기화 취소됨 (Dialog 닫힘)"); - - return; - } - - WebViewer( - { - path: "/pdftronWeb", - licenseKey: process.env.NEXT_PUBLIC_PDFTRON_WEBVIEW_KEY, - fullAPI: true, - css: "/globals.css", - }, - viewer.current as HTMLDivElement - ).then(async (instance: WebViewerInstance) => { - setInstance(instance); - instance.UI.enableFeatures([instance.UI.Feature.MultiTab]); - instance.UI.disableElements([ - "addTabButton", - "multiTabsEmptyPage", - ]); - setViewerLoading(false); -======= requestAnimationFrame(() => { if (viewer.current) { @@ -237,21 +122,11 @@ function DocumentViewer({open, setOpen, versions}){ instance.UI.disableElements(["addTabButton", "multiTabsEmptyPage"]); setViewerLoading(false); ->>>>>>> cac978d5c77e9b30165e4fbe6930eeac9862204d }); }); } }); } -<<<<<<< HEAD - - return () => { - // cleanup 시에는 중단 flag 세움 - if (instance) { - instance.UI.dispose(); - } - setTimeout(() => cleanupHtmlStyle(), 500); -======= return async () => { // cleanup 시에는 중단 flag 세움 @@ -259,78 +134,10 @@ function DocumentViewer({open, setOpen, versions}){ await instance.UI.dispose() } await setTimeout(() => cleanupHtmlStyle(), 500) ->>>>>>> cac978d5c77e9b30165e4fbe6930eeac9862204d }; }, [open]); React.useEffect(() => { -<<<<<<< HEAD - const loadDocument = async () => { - if (instance && versions.length > 0) { - const { UI } = instance; - - const optionsArray: any[] = []; - - versions.forEach((c) => { - const { attachments } = c; - attachments.forEach((c2) => { - const { fileName, filePath, fileType } = c2; - - const fileTypeCur = fileType ?? ""; - - const options = { - filename: fileName, - ...(fileTypeCur.includes("xlsx") && { - officeOptions: { - formatOptions: { - applyPageBreaksToSheet: true, - }, - }, - }), - }; - - optionsArray.push({ - filePath, - options, - }); - }); - }); - - const tabIds = []; - - for (const option of optionsArray) { - const { filePath, options } = option; - const response = await fetch(filePath); - const blob = await response.blob(); - - const tab = await UI.TabManager.addTab(blob, options); - tabIds.push(tab); // 탭 ID 저장 - } - - if (tabIds.length > 0) { - await UI.TabManager.setActiveTab(tabIds[0]); - } - - setFileSetLoading(false); - } - }; - loadDocument(); - }, [instance, versions]); - - return ( - { - console.log({ val, fileSetLoading }); - if (!val && fileSetLoading) { - return; - } - - if (instance) { - try { - await instance.UI.dispose(); - setInstance(null); // 상태도 초기화 -======= const loadDocument = async () => { if(instance && versions.length > 0){ @@ -395,42 +202,10 @@ function DocumentViewer({open, setOpen, versions}){ await instance.UI.dispose(); setInstance(null); // 상태도 초기화 ->>>>>>> cac978d5c77e9b30165e4fbe6930eeac9862204d } catch (e) { console.warn("dispose error", e); } } -<<<<<<< HEAD - - // cleanupHtmlStyle() - setViewerLoading(false); - setOpen((prev) => !prev); - await setTimeout(() => cleanupHtmlStyle(), 1000); - }} - > - - - 문서 미리보기 - 첨부파일 미리보기 - -
- {viwerLoading && ( -
- -

- 문서 뷰어 로딩 중... -

-
- )} -
-
-
- ); -}; -======= // cleanupHtmlStyle() setViewerLoading(false); @@ -455,5 +230,4 @@ function DocumentViewer({open, setOpen, versions}){ ); -} ->>>>>>> cac978d5c77e9b30165e4fbe6930eeac9862204d +} \ No newline at end of file diff --git a/components/form-data/form-data-table.tsx b/components/form-data/form-data-table.tsx index 9feaf3b2..25a005d1 100644 --- a/components/form-data/form-data-table.tsx +++ b/components/form-data/form-data-table.tsx @@ -531,14 +531,14 @@ export default function DynamicTable({ size="sm" onClick={() => setBatchDownDialog(true)} > - Report Batch + Batch + + + + ) +} \ No newline at end of file diff --git a/lib/po/table/item-dialog.tsx b/lib/po/table/item-dialog.tsx new file mode 100644 index 00000000..a6690e75 --- /dev/null +++ b/lib/po/table/item-dialog.tsx @@ -0,0 +1,173 @@ +"use client" + +import * as React from "react" +import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter } from "@/components/ui/dialog" +import { Button } from "@/components/ui/button" +import { ScrollArea } from "@/components/ui/scroll-area" +import { Separator } from "@/components/ui/separator" +import { Badge } from "@/components/ui/badge" +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table" +import { Package, Info, DollarSign, Tag, Clock, Hash } from "lucide-react" + +import type { ContractDetailParsed } from "@/db/schema/contract" + +interface ItemsDialogProps { + open: boolean + onOpenChange: (open: boolean) => void + po: ContractDetailParsed | null +} + +export function ItemsDialog({ open, onOpenChange, po }: ItemsDialogProps) { + console.log(po) + + // Format currency with appropriate symbol + const formatCurrency = (value: number | null, currency?: string) => { + if (value === null) return '-'; + const currencySymbol = currency === 'USD' ? '$' : currency || ''; + return `${currencySymbol}${value.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`; + }; + + // Format date to a readable format + const formatDate = (dateString: string) => { + const date = new Date(dateString); + return date.toLocaleString(); + }; + + return ( + + + + + + Contract Items + + + {po + ? `Item list for contract #${po.contractNo} - ${po.contractName}` + : "No contract selected." + } + + + + {/* Main content */} + {po ? ( + po.items.length === 0 ? ( +
+ + No items found for this contract. +
+ ) : ( +
+
+
+ Total Items: {po.items.length} +
+
+ Currency: {po.currency || "Default"} +
+
+ + +
+ {po.items.map((item) => ( + + +
+ + + Item #{item.itemId} + + {item.quantity > 1 && ( + + Qty: {item.quantity} + + )} +
+
+ + {item.description && ( +
+
+ + Description +
+
{item.description}
+
+ )} + +
+ + + Unit Price + + {item.unitPrice !== null ? ( +
+ + {formatCurrency(item.unitPrice, po.currency??"KRW")} +
+ ) : "-"} +
+
+ + {item.taxRate !== null && ( + + Tax Rate + {item.taxRate}% + + )} + + {item.taxAmount !== null && ( + + Tax Amount + {formatCurrency(item.taxAmount, po.currency??"KRW")} + + )} + + {item.totalLineAmount !== null && ( + + Total Amount + + {formatCurrency(item.totalLineAmount, po.currency??"KRW")} + + + )} +
+
+ + {item.remark && ( +
+
+ + Remark +
+
{item.remark}
+
+ )} + +
+ + Updated: {formatDate(item.updatedAt)} +
+ + + ))} +
+ +
+ ) + ) : ( +
+ Please select a contract to see its items. +
+ )} + + + + + + + ) +} \ No newline at end of file diff --git a/lib/po/table/po-table-columns.tsx b/lib/po/table/po-table-columns.tsx index a13b2acf..6517b9b3 100644 --- a/lib/po/table/po-table-columns.tsx +++ b/lib/po/table/po-table-columns.tsx @@ -3,7 +3,7 @@ import * as React from "react" import { type DataTableRowAction } from "@/types/table" import { type ColumnDef } from "@tanstack/react-table" -import { InfoIcon, PenIcon } from "lucide-react" +import { InfoIcon, FileTextIcon, SendIcon, FileSignatureIcon, MoreHorizontalIcon, ExternalLinkIcon } from "lucide-react" import { formatDate } from "@/lib/utils" import { Button } from "@/components/ui/button" @@ -13,19 +13,28 @@ import { TooltipProvider, TooltipTrigger, } from "@/components/ui/tooltip" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import { Badge } from "@/components/ui/badge" import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header" import { poColumnsConfig } from "@/config/poColumnsConfig" -import { ContractDetail } from "@/db/schema/contract" +import { ContractDetailParsed } from "@/db/schema/contract" interface GetColumnsProps { - setRowAction: React.Dispatch | null>> + setRowAction: React.Dispatch | null>> } /** * tanstack table column definitions with nested headers */ -export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef[] { +export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef[] { // ---------------------------------------------------------------- // 1) select column (checkbox) - if needed // ---------------------------------------------------------------- @@ -33,164 +42,229 @@ export function getColumns({ setRowAction }: GetColumnsProps): ColumnDef = { + const actionsColumn: ColumnDef = { id: "actions", enableHiding: false, + header: () =>
Actions
, cell: function Cell({ row }) { // Check if this contract already has a signature envelope const hasSignature = row.original.hasSignature; - + const contract = row.original; + return ( -
- {/* Item Info Button */} +
+ {/* Items Button - Visually distinct with badge showing count */} - View Item Info + View contract items and details - - {/* Signature Request Button - only show if no signature exists */} - {!hasSignature && ( + + {/* Signature related actions */} + {hasSignature ? ( + + + + + + + View signature status and details + + + + ) : ( - Request Electronic Signature + Send electronic signature requests )} + + {/* Alternative: Dropdown menu for more actions */} + {/* + + + + + + Actions + setRowAction({ row, type: "items" })}> + + View Items + + + {hasSignature ? ( + setRowAction({ row, type: "esign-detail" })}> + + View Signatures + + ) : ( + setRowAction({ row, type: "signature" })}> + + Request Signatures + + )} + + + */}
); }, - size: 80, // Increased width to accommodate both buttons + size: 340, // Adjusted for multiple buttons + minSize:280 }; // ---------------------------------------------------------------- // 3) Regular columns grouped by group name // ---------------------------------------------------------------- - // 3-1) groupMap: { [groupName]: ColumnDef[] } - const groupMap: Record[]> = {}; - - // (1) JSON config를 읽어서 ColumnDef를 생성하는 부분 (일부 발췌) -poColumnsConfig.forEach((cfg) => { - const groupName = cfg.group || "_noGroup" - if (!groupMap[groupName]) { - groupMap[groupName] = [] - } - - let childCol: ColumnDef - - if (cfg.type === "custom" && cfg.customType === "esignStatus") { - // ======================================== - // (2) 전자서명 전용 커스텀 컬럼 - // ======================================== - childCol = { - id: cfg.id, - header: ({ column }) => ( - - ), - // 여기서 row.original.envelopes 등 활용하여 최신 전자서명 상태 표시 - cell: ({ row }) => { - const data = row.original - if (!data.envelopes || data.envelopes.length === 0) { + // 3-1) groupMap: { [groupName]: ColumnDef[] } + const groupMap: Record[]> = {}; + + // (1) JSON config를 읽어서 ColumnDef를 생성하는 부분 (일부 발췌) + poColumnsConfig.forEach((cfg) => { + const groupName = cfg.group || "_noGroup" + if (!groupMap[groupName]) { + groupMap[groupName] = [] + } + + let childCol: ColumnDef + + if (cfg.type === "custom") { + // ======================================== + // (2) 전자서명 전용 커스텀 컬럼 + // ======================================== + childCol = { + id: cfg.id, + header: ({ column }) => ( + + ), + // 여기서 row.original.envelopes 등 활용하여 최신 전자서명 상태 표시 + cell: ({ row }) => { + const data = row.original + if (!data.envelopes || data.envelopes.length === 0) { + return ( +
+ No E-Sign +
+ ) + } + + // envelopes가 여러 개 있으면 최신(가장 최근 updatedAt) 가져오기 + const sorted = [...data.envelopes].sort((a, b) => { + const dateA = new Date(a.updatedAt) + const dateB = new Date(b.updatedAt) + return dateB.getTime() - dateA.getTime() + }) + const latest = sorted[0] + + const status = latest.envelopeStatus; + + if (!status) { + // status가 null이면, 기본 색상이나 별도 표시 + return No Status + } + + const colorMap: Record = { + completed: "text-green-600", + sent: "text-blue-600", + voided: "text-red-600", + }; + + const colorClass = colorMap[status] ?? "text-gray-700"; + return ( -
- No E-Sign +
+ setRowAction({ row, type: "esign-detail" })} + className={`${colorClass} cursor-pointer flex items-center`} + > + {status} + +
) - } - - // envelopes가 여러 개 있으면 최신(가장 최근 updatedAt) 가져오기 - const sorted = [...data.envelopes].sort((a, b) => { - const dateA = new Date(a.updatedAt) - const dateB = new Date(b.updatedAt) - return dateB.getTime() - dateA.getTime() - }) - const latest = sorted[0] - - // 상태에 따라 다른 UI 색상/아이콘 - const status = latest.envelopeStatus // "sent", "completed", ... - const colorMap: Record = { - completed: "text-green-600", - sent: "text-blue-600", - voided: "text-red-600", + }, + meta: { + excelHeader: cfg.excelHeader, + group: cfg.group, + type: cfg.type, + }, + } + } else { + // ======================================== + // (3) 일반 컬럼 (type: text/date/number 등) + // ======================================== + childCol = { + accessorKey: cfg.id, + enableResizing: true, + header: ({ column }) => ( + + ), + meta: { + excelHeader: cfg.excelHeader, + group: cfg.group, + type: cfg.type, + }, + cell: ({ row, cell }) => { + // 날짜 포맷, 숫자 포맷 등 처리 + if (cfg.type === "date") { + const dateVal = cell.getValue() as Date + return formatDate(dateVal) + } // ... - } - const colorClass = colorMap[status] || "text-gray-700" - - return ( - - ) - }, - meta: { - excelHeader: cfg.excelHeader, - group: cfg.group, - type: cfg.type, - }, - } - } else { - // ======================================== - // (3) 일반 컬럼 (type: text/date/number 등) - // ======================================== - childCol = { - accessorKey: cfg.id, - enableResizing: true, - header: ({ column }) => ( - - ), - meta: { - excelHeader: cfg.excelHeader, - group: cfg.group, - type: cfg.type, - }, - cell: ({ row, cell }) => { - // 날짜 포맷, 숫자 포맷 등 처리 - if (cfg.type === "date") { - const dateVal = cell.getValue() as Date - return formatDate(dateVal) - } - // ... - return row.getValue(cfg.id) ?? "" - }, + return row.getValue(cfg.id) ?? "" + }, + } } - } - groupMap[groupName].push(childCol) -}) + groupMap[groupName].push(childCol) + }) // ---------------------------------------------------------------- // 3-2) Create actual parent columns (groups) from the groupMap // ---------------------------------------------------------------- - const nestedColumns: ColumnDef[] = []; + const nestedColumns: ColumnDef[] = []; // Order can be fixed by pre-defining group order or sorting // Here we just use Object.entries order diff --git a/lib/po/table/po-table-toolbar-actions.tsx b/lib/po/table/po-table-toolbar-actions.tsx index e6c8e79a..23507751 100644 --- a/lib/po/table/po-table-toolbar-actions.tsx +++ b/lib/po/table/po-table-toolbar-actions.tsx @@ -7,12 +7,12 @@ import { toast } from "sonner" import { exportTableToExcel } from "@/lib/export" import { Button } from "@/components/ui/button" -import { ContractDetail } from "@/db/schema/contract" +import { ContractDetailParsed } from "@/db/schema/contract" interface ItemsTableToolbarActionsProps { - table: Table + table: Table } export function PoTableToolbarActions({ table }: ItemsTableToolbarActionsProps) { diff --git a/lib/po/table/po-table.tsx b/lib/po/table/po-table.tsx index 49fbdda4..9175037b 100644 --- a/lib/po/table/po-table.tsx +++ b/lib/po/table/po-table.tsx @@ -15,9 +15,11 @@ import { toast } from "sonner" import { getPOs, requestSignatures } from "../service" import { getColumns } from "./po-table-columns" -import { ContractDetail } from "@/db/schema/contract" +import { ContractDetail, ContractDetailParsed, Envelope } from "@/db/schema/contract" import { PoTableToolbarActions } from "./po-table-toolbar-actions" import { SignatureRequestModal } from "./sign-request-dialog" +import { EsignStatusDialog } from "./esign-dialog" +import { ItemsDialog } from "./item-dialog" interface ItemsTableProps { promises: Promise< @@ -36,40 +38,106 @@ interface SigningParty { vendorContactId?: number; } +export function transformContractData(data: ContractDetail[]): ContractDetailParsed[] { + return data.map((contract) => { + let parsedEnvelopes: Envelope[] = []; + let parsedItems = []; + + try { + // Check if envelopes is a string that needs parsing + if (typeof contract.envelopes === "string") { + parsedEnvelopes = JSON.parse(contract.envelopes); + } else if (Array.isArray(contract.envelopes)) { + // If it's already an array, use it directly + parsedEnvelopes = contract.envelopes as unknown as Envelope[]; + } + + // Check if items is a string that needs parsing + if (typeof contract.items === "string") { + parsedItems = JSON.parse(contract.items); + } else if (Array.isArray(contract.items)) { + // If it's already an array, use it directly + parsedItems = contract.items; + } + } catch (err) { + console.error("Error parsing JSON", err); + } + + // Return a new object with all properties from the original contract + // but replace envelopes and items with their parsed versions + return { + ...contract, + envelopes: parsedEnvelopes, + items: parsedItems + } as ContractDetailParsed; + }); +} export function PoListsTable({ promises }: ItemsTableProps) { const { featureFlags } = useFeatureFlags() - - const [{ data, pageCount }] = - React.use(promises) - - const [rowAction, setRowAction] = - React.useState | null>(null) - + + const [rawData, setRawData] = React.useState<{ + data: ContractDetail[]; + pageCount: number; + }>({ data: [], pageCount: 0 }); + + // Add state for transformed data + const [transformedData, setTransformedData] = React.useState<{ + data: ContractDetailParsed[]; + pageCount: number; + }>({ data: [], pageCount: 0 }); + + console.log(rawData) + console.log(transformedData) + + // Load raw data from promises + React.useEffect(() => { + promises.then(([result]) => { + console.log(result.data) + + setRawData(result); + // Transform the data + setTransformedData({ + data: transformContractData(result.data), + pageCount: result.pageCount + }); + }); + }, [promises]); + + const [rowAction, setRowAction] = + React.useState | null>(null) + // State for signature request modal const [signatureModalOpen, setSignatureModalOpen] = React.useState(false) - const [selectedContract, setSelectedContract] = React.useState(null) - + const [signatureDetailOpen, setSignatureDetailOpen] = React.useState(false) + const [itemsOpen, setItemsOpen] = React.useState(false) + const [selectedContract, setSelectedContract] = React.useState(null) + // Handle row actions React.useEffect(() => { if (!rowAction) return - + if (rowAction.type === "signature") { // Open signature request modal with the selected contract setSelectedContract(rowAction.row.original) setSignatureModalOpen(true) setRowAction(null) } else if (rowAction.type === "items") { - // Existing handler for "items" action type - // Your existing code here + setSelectedContract(rowAction.row.original) + setItemsOpen(true) setRowAction(null) + } else if (rowAction.type === "esign-detail") { + setSignatureDetailOpen(true) + setSelectedContract(rowAction.row.original) + console.log("E-sign details for contract:", rowAction.row.original); + setRowAction(null); } }, [rowAction]) - + const columns = React.useMemo( () => getColumns({ setRowAction }), [setRowAction] ) - + // Updated handler to work with multiple signers const handleSignatureRequest = async ( values: { signers: SigningParty[] }, @@ -80,7 +148,7 @@ export function PoListsTable({ promises }: ItemsTableProps) { contractId, signers: values.signers }); - + // Handle the result if (result.success) { toast.success(result.message || "Signature requests sent successfully"); @@ -93,11 +161,11 @@ export function PoListsTable({ promises }: ItemsTableProps) { } } - const filterFields: DataTableFilterField[] = [ + const filterFields: DataTableFilterField[] = [ // Your existing filter fields ] - const advancedFilterFields: DataTableAdvancedFilterField[] = [ + const advancedFilterFields: DataTableAdvancedFilterField[] = [ { id: "contractNo", label: "Contract No", @@ -119,11 +187,11 @@ export function PoListsTable({ promises }: ItemsTableProps) { type: "date", }, ] - + const { table } = useDataTable({ - data, + data: transformedData.data, // Use the transformed data columns, - pageCount, + pageCount: transformedData.pageCount, filterFields, enablePinning: true, enableAdvancedFilter: true, @@ -149,7 +217,20 @@ export function PoListsTable({ promises }: ItemsTableProps) { - + + + + + + {/* Enhanced Dual Signature Request Modal */} {selectedContract && ( void onSubmit: ( @@ -217,7 +218,7 @@ export function SignatureRequestModal({ return ( - + Request Electronic Signatures @@ -225,185 +226,191 @@ export function SignatureRequestModal({ -
- - - {/* Requester Signature Section */} - -
- ( - - - + + + + {/* Requester Signature Section */} + +
+ ( + + + + + +
Requester Signature
+
+
+ )} + /> +
+ + {form.watch("includeRequesterSigner") && ( + + + ( + + Signer Email + + + + + + )} /> -
- -
Requester Signature
-
-
- )} - /> -
- - {form.watch("includeRequesterSigner") && ( - - - ( - - Signer Email - - - - - - )} - /> - - ( - - Signer Name - - - - - - )} - /> - - ( - - Signer Position - - - - - - )} - /> - - - )} - -
- - {/* Vendor Signature Section */} - -
- ( - - - ( + + Signer Name + + + + + + )} /> - - -
Vendor Signature
-
-
- )} - /> -
- - {form.watch("includeVendorSigner") && ( - - - ( - - Select Vendor Contact - - - {vendorContacts.length > 0 ? ( - vendorContacts.map((contact) => ( - - {contact.contactName} {contact.isPrimary ? "(Primary)" : ""} + + + )} + /> + + + )} + +
+ + {/* Vendor Signature Section */} + +
+ ( + + + + + +
Vendor Signature
+
+
+ )} + /> +
+ + {form.watch("includeVendorSigner") && ( + + + ( + + Select Vendor Contact + - - + )} + + + + + )} + /> + + {/* Display selected contact info (read-only) */} + {selectedVendorContact && ( + <> + + Contact Email +
+ {selectedVendorContact.contactEmail} +
+
+ + + Contact Name +
+ {selectedVendorContact.contactName} +
+
+ + + Contact Position +
+ {selectedVendorContact.contactPosition || "N/A"} +
+
+ )} - /> - - {/* Display selected contact info (read-only) */} - {selectedVendorContact && ( - <> - - Contact Email -
- {selectedVendorContact.contactEmail} -
-
- - - Contact Name -
- {selectedVendorContact.contactName} -
-
- - - Contact Position -
- {selectedVendorContact.contactPosition || "N/A"} -
-
- - )} -
-
- )} -
-
-
- - - - - -
- + + + )} + + + + + +
+ + + + +
+ + +
) diff --git a/package-lock.json b/package-lock.json index d41582f4..a6580733 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7612,6 +7612,7 @@ "version": "3.5.2", "resolved": "https://registry.npmjs.org/formidable/-/formidable-3.5.2.tgz", "integrity": "sha512-Jqc1btCy3QzRbJaICGwKcBfGWuLADRerLzDqi2NwSt/UkXLsHJw2TVResiaoBufHVHy9aSgClOHCeJsSsFLTbg==", + "license": "MIT", "dependencies": { "dezalgo": "^1.0.4", "hexoid": "^2.0.0", diff --git a/types/table.d.ts b/types/table.d.ts index 207a0c19..979f2f27 100644 --- a/types/table.d.ts +++ b/types/table.d.ts @@ -54,7 +54,7 @@ export type Filter = Prettify< export interface DataTableRowAction { row: Row - type: "responseDetail"|"signature"|"update" | "delete" | "user" | "pemission" | "invite" | "items" | "attachment" |"comments" | "open" | "select" | "files" + type: "esign-detail"| "responseDetail"|"signature"|"update" | "delete" | "user" | "pemission" | "invite" | "items" | "attachment" |"comments" | "open" | "select" | "files" } export interface QueryBuilderOpts { -- cgit v1.2.3