From 39062e1773136cbe8e13dbc9e6304e6e121ea5c7 Mon Sep 17 00:00:00 2001 From: kyy Date: Thu, 26 Feb 2026 13:58:20 +0900 Subject: [PATCH] =?UTF-8?q?Consent=20=EB=AA=A9=EB=A1=9D=20CSV=20=EB=82=B4?= =?UTF-8?q?=EB=B3=B4=EB=82=B4=EA=B8=B0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../features/clients/ClientConsentsPage.tsx | 58 ++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/devfront/src/features/clients/ClientConsentsPage.tsx b/devfront/src/features/clients/ClientConsentsPage.tsx index e7e17685..75bafe57 100644 --- a/devfront/src/features/clients/ClientConsentsPage.tsx +++ b/devfront/src/features/clients/ClientConsentsPage.tsx @@ -80,6 +80,56 @@ function ClientConsentsPage() { return scopeFilter === "all" || row.grantedScopes.includes(scopeFilter); }); + const handleExportCSV = () => { + if (filteredRows.length === 0) return; + + const headers = [ + t("ui.dev.clients.consents.table.user", "User"), + t("ui.dev.clients.consents.table.tenant", "Tenant"), + t("ui.dev.clients.table.status", "Status"), + t("ui.dev.clients.consents.table.scopes", "Granted Scopes"), + t("ui.dev.clients.consents.table.first_granted", "First Granted"), + t( + "ui.dev.clients.consents.table.last_auth", + "Last Authenticated / Revoked", + ), + ]; + + const csvContent = [ + headers.join(","), + ...filteredRows.map((row) => { + const lastAuthRevoked = + row.status === "revoked" && row.deletedAt + ? `${t("ui.dev.clients.consents.status_revoked", "Revoked")}: ${new Date(row.deletedAt).toLocaleString()}` + : row.authenticatedAt + ? new Date(row.authenticatedAt).toLocaleString() + : "-"; + + return [ + `"${row.subject} (${row.userName || ""})"`, + `"${row.tenantName || row.tenantId || ""}"`, + `"${row.status}"`, + `"${row.grantedScopes.join(", ")}"`, + `"${new Date(row.createdAt).toLocaleString()}"`, + `"${lastAuthRevoked}"`, + ].join(","); + }), + ].join("\n"); + + const blob = new Blob(["\uFEFF" + csvContent], { + type: "text/csv;charset=utf-8;", + }); + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + const date = new Date().toISOString().split("T")[0]; + link.setAttribute("href", url); + link.setAttribute("download", `consents_${clientId}_${date}.csv`); + link.style.visibility = "hidden"; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + }; + return (
@@ -191,7 +241,11 @@ function ClientConsentsPage() { > {t("ui.common.search", "검색")} -
@@ -455,6 +509,8 @@ function ClientConsentsPage() { {rows.reduce((acc, row) => acc + row.grantedScopes.length, 0)} + +

{t(