forked from baron/baron-sso
테스트 커버리지 보강 및 공통 유틸 테스트 추가
This commit is contained in:
77
devfront/src/components/common/LanguageSelector.test.tsx
Normal file
77
devfront/src/components/common/LanguageSelector.test.tsx
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import { act } from "react";
|
||||||
|
import { createRoot, type Root } from "react-dom/client";
|
||||||
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
vi.mock("../../lib/i18n", () => ({
|
||||||
|
t: (_key: string, fallback?: string) => fallback ?? _key,
|
||||||
|
}));
|
||||||
|
|
||||||
|
import LanguageSelector from "./LanguageSelector";
|
||||||
|
|
||||||
|
const roots: Root[] = [];
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
window.localStorage.clear();
|
||||||
|
window.history.replaceState({}, "", "/");
|
||||||
|
document.body.innerHTML = "";
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
for (const root of roots.splice(0)) {
|
||||||
|
act(() => {
|
||||||
|
root.unmount();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
vi.restoreAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
function renderSelector() {
|
||||||
|
const container = document.createElement("div");
|
||||||
|
document.body.appendChild(container);
|
||||||
|
const root = createRoot(container);
|
||||||
|
roots.push(root);
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
root.render(<LanguageSelector />);
|
||||||
|
});
|
||||||
|
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("LanguageSelector", () => {
|
||||||
|
it("prefers the locale stored in localStorage", () => {
|
||||||
|
window.localStorage.setItem("locale", "en");
|
||||||
|
|
||||||
|
const container = renderSelector();
|
||||||
|
const select = container.querySelector("select") as HTMLSelectElement;
|
||||||
|
|
||||||
|
expect(select.value).toBe("en");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("falls back to the path locale when storage is empty", () => {
|
||||||
|
window.history.replaceState({}, "", "/ko");
|
||||||
|
|
||||||
|
const container = renderSelector();
|
||||||
|
const select = container.querySelector("select") as HTMLSelectElement;
|
||||||
|
|
||||||
|
expect(select.value).toBe("ko");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("saves the selected locale and dispatches a development event", () => {
|
||||||
|
vi.stubEnv("MODE", "development");
|
||||||
|
const dispatchEvent = vi.spyOn(window, "dispatchEvent");
|
||||||
|
window.history.replaceState({}, "", "/ko");
|
||||||
|
|
||||||
|
const container = renderSelector();
|
||||||
|
const select = container.querySelector("select") as HTMLSelectElement;
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
select.value = "en";
|
||||||
|
select.dispatchEvent(new Event("change", { bubbles: true }));
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(window.localStorage.getItem("locale")).toBe("en");
|
||||||
|
expect(dispatchEvent).toHaveBeenCalled();
|
||||||
|
expect(select.value).toBe("en");
|
||||||
|
});
|
||||||
|
});
|
||||||
82
devfront/src/components/ui/copy-button.test.tsx
Normal file
82
devfront/src/components/ui/copy-button.test.tsx
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import { act } from "react";
|
||||||
|
import { createRoot, type Root } from "react-dom/client";
|
||||||
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||||
|
import { CopyButton } from "./copy-button";
|
||||||
|
|
||||||
|
const roots: Root[] = [];
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
for (const root of roots.splice(0)) {
|
||||||
|
act(() => {
|
||||||
|
root.unmount();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
vi.restoreAllMocks();
|
||||||
|
delete (navigator as Navigator & { clipboard?: unknown }).clipboard;
|
||||||
|
Object.defineProperty(window, "isSecureContext", {
|
||||||
|
value: false,
|
||||||
|
configurable: true,
|
||||||
|
});
|
||||||
|
document.body.innerHTML = "";
|
||||||
|
});
|
||||||
|
|
||||||
|
function renderCopyButton(value: string, onCopy = vi.fn()) {
|
||||||
|
const container = document.createElement("div");
|
||||||
|
document.body.appendChild(container);
|
||||||
|
const root = createRoot(container);
|
||||||
|
roots.push(root);
|
||||||
|
|
||||||
|
act(() => {
|
||||||
|
root.render(<CopyButton value={value} onCopy={onCopy} />);
|
||||||
|
});
|
||||||
|
|
||||||
|
return { container, onCopy };
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("CopyButton", () => {
|
||||||
|
it("copies with the clipboard API when secure context is available", async () => {
|
||||||
|
const writeText = vi.fn().mockResolvedValue(undefined);
|
||||||
|
Object.defineProperty(navigator, "clipboard", {
|
||||||
|
value: { writeText },
|
||||||
|
configurable: true,
|
||||||
|
});
|
||||||
|
Object.defineProperty(window, "isSecureContext", {
|
||||||
|
value: true,
|
||||||
|
configurable: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { container, onCopy } = renderCopyButton("client-secret");
|
||||||
|
const button = container.querySelector("button");
|
||||||
|
expect(button).not.toBeNull();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
button?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(writeText).toHaveBeenCalledWith("client-secret");
|
||||||
|
expect(onCopy).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("falls back to execCommand when clipboard API is unavailable", async () => {
|
||||||
|
const execCommand = vi.fn(() => true);
|
||||||
|
Object.defineProperty(document, "execCommand", {
|
||||||
|
value: execCommand,
|
||||||
|
configurable: true,
|
||||||
|
});
|
||||||
|
Object.defineProperty(window, "isSecureContext", {
|
||||||
|
value: false,
|
||||||
|
configurable: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { container, onCopy } = renderCopyButton("client-secret");
|
||||||
|
const button = container.querySelector("button");
|
||||||
|
expect(button).not.toBeNull();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
button?.dispatchEvent(new MouseEvent("click", { bubbles: true }));
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(execCommand).toHaveBeenCalledWith("copy");
|
||||||
|
expect(onCopy).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
72
devfront/src/features/coverage/commonAudit.test.ts
Normal file
72
devfront/src/features/coverage/commonAudit.test.ts
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import {
|
||||||
|
formatAuditDateParts,
|
||||||
|
formatAuditValue,
|
||||||
|
parseAuditDetails,
|
||||||
|
resolveAuditAction,
|
||||||
|
resolveAuditActor,
|
||||||
|
resolveAuditTarget,
|
||||||
|
} from "../../../../common/core/audit";
|
||||||
|
|
||||||
|
describe("common audit helpers", () => {
|
||||||
|
it("parses audit details and falls back on invalid payloads", () => {
|
||||||
|
expect(parseAuditDetails()).toEqual({});
|
||||||
|
expect(parseAuditDetails("not-json")).toEqual({});
|
||||||
|
expect(parseAuditDetails('{"action":"ADD_RELATION"}')).toEqual({
|
||||||
|
action: "ADD_RELATION",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("formats audit values and dates", () => {
|
||||||
|
const circular: Record<string, unknown> = {};
|
||||||
|
circular.self = circular;
|
||||||
|
|
||||||
|
expect(formatAuditValue(null)).toBe("-");
|
||||||
|
expect(formatAuditValue("hello")).toBe("hello");
|
||||||
|
expect(formatAuditValue({ a: 1 })).toBe('{"a":1}');
|
||||||
|
expect(formatAuditValue(circular)).toBe("[object Object]");
|
||||||
|
|
||||||
|
expect(formatAuditDateParts("")).toEqual({ date: "-", time: "-" });
|
||||||
|
expect(formatAuditDateParts("invalid")).toEqual({
|
||||||
|
date: "invalid",
|
||||||
|
time: "-",
|
||||||
|
});
|
||||||
|
|
||||||
|
const parsed = formatAuditDateParts("2026-05-27T07:43:39.000Z");
|
||||||
|
expect(parsed.date).toBe("2026-05-27");
|
||||||
|
expect(parsed.time).not.toBe("-");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("resolves audit actor, action, and target consistently", () => {
|
||||||
|
expect(
|
||||||
|
resolveAuditActor(
|
||||||
|
{ user_id: "actor-1" },
|
||||||
|
{ actor_id: "actor-2" },
|
||||||
|
),
|
||||||
|
).toBe("actor-1");
|
||||||
|
expect(
|
||||||
|
resolveAuditActor({ user_id: "" }, { actor_id: "actor-2" }),
|
||||||
|
).toBe("actor-2");
|
||||||
|
expect(resolveAuditActor({ user_id: "" }, {})).toBe("-");
|
||||||
|
|
||||||
|
expect(
|
||||||
|
resolveAuditAction(
|
||||||
|
{ event_type: "UPDATE_CLIENT" },
|
||||||
|
{ action: "ADD_RELATION" },
|
||||||
|
),
|
||||||
|
).toBe("ADD_RELATION");
|
||||||
|
expect(
|
||||||
|
resolveAuditAction(
|
||||||
|
{ event_type: "UPDATE_CLIENT" },
|
||||||
|
{ method: "POST", path: "/dev/clients" },
|
||||||
|
),
|
||||||
|
).toBe("POST /dev/clients");
|
||||||
|
expect(resolveAuditAction({ event_type: "UPDATE_CLIENT" }, {})).toBe(
|
||||||
|
"UPDATE_CLIENT",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(resolveAuditTarget({ target: "target-1" })).toBe("target-1");
|
||||||
|
expect(resolveAuditTarget({ target_id: "target-2" })).toBe("target-2");
|
||||||
|
expect(resolveAuditTarget({})).toBe("-");
|
||||||
|
});
|
||||||
|
});
|
||||||
72
devfront/src/features/coverage/commonAuth.test.ts
Normal file
72
devfront/src/features/coverage/commonAuth.test.ts
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import {
|
||||||
|
DEFAULT_OIDC_REDIRECT_PATH,
|
||||||
|
DEFAULT_OIDC_SCOPE,
|
||||||
|
buildCommonOidcRuntimeConfig,
|
||||||
|
buildCommonUserManagerSettings,
|
||||||
|
shouldStartLoginRedirect,
|
||||||
|
} from "../../../../common/core/auth";
|
||||||
|
|
||||||
|
describe("common auth helpers", () => {
|
||||||
|
it("builds the runtime OIDC config with sensible defaults", () => {
|
||||||
|
const config = buildCommonOidcRuntimeConfig({
|
||||||
|
authority: "https://issuer.example.com",
|
||||||
|
clientId: "client-1",
|
||||||
|
userStore: { kind: "store" },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(config).toEqual({
|
||||||
|
authority: "https://issuer.example.com",
|
||||||
|
client_id: "client-1",
|
||||||
|
redirect_uri: `${window.location.origin}${DEFAULT_OIDC_REDIRECT_PATH}`,
|
||||||
|
response_type: "code",
|
||||||
|
scope: DEFAULT_OIDC_SCOPE,
|
||||||
|
post_logout_redirect_uri: window.location.origin,
|
||||||
|
popup_redirect_uri: `${window.location.origin}${DEFAULT_OIDC_REDIRECT_PATH}`,
|
||||||
|
userStore: { kind: "store" },
|
||||||
|
automaticSilentRenew: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("copies user manager config and fills missing string fields", () => {
|
||||||
|
expect(
|
||||||
|
buildCommonUserManagerSettings({
|
||||||
|
authority: "https://issuer.example.com",
|
||||||
|
}),
|
||||||
|
).toEqual({
|
||||||
|
authority: "https://issuer.example.com",
|
||||||
|
client_id: "",
|
||||||
|
redirect_uri: "",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("decides when to start login redirects", () => {
|
||||||
|
expect(
|
||||||
|
shouldStartLoginRedirect({
|
||||||
|
pathname: "/clients",
|
||||||
|
isRedirecting: false,
|
||||||
|
}),
|
||||||
|
).toBe(true);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
shouldStartLoginRedirect({
|
||||||
|
pathname: "/login",
|
||||||
|
isRedirecting: false,
|
||||||
|
}),
|
||||||
|
).toBe(false);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
shouldStartLoginRedirect({
|
||||||
|
pathname: `${DEFAULT_OIDC_REDIRECT_PATH}/callback`,
|
||||||
|
isRedirecting: false,
|
||||||
|
}),
|
||||||
|
).toBe(false);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
shouldStartLoginRedirect({
|
||||||
|
pathname: "/clients",
|
||||||
|
isRedirecting: true,
|
||||||
|
}),
|
||||||
|
).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
201
devfront/src/features/overview/recentClientChanges.test.ts
Normal file
201
devfront/src/features/overview/recentClientChanges.test.ts
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
import { beforeEach, describe, expect, it } from "vitest";
|
||||||
|
import type { ClientSummary, DevAuditLog } from "../../lib/devApi";
|
||||||
|
import {
|
||||||
|
buildRecentClientChangeDetails,
|
||||||
|
buildRecentClientChanges,
|
||||||
|
getRecentClientActionLabel,
|
||||||
|
} from "./recentClientChanges";
|
||||||
|
|
||||||
|
function makeClient(id: string, name = id): ClientSummary {
|
||||||
|
return {
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
type: "private",
|
||||||
|
status: "active",
|
||||||
|
createdAt: "2026-05-27T00:00:00.000Z",
|
||||||
|
redirectUris: [],
|
||||||
|
scopes: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeAuditLog(
|
||||||
|
eventId: string,
|
||||||
|
timestamp: string,
|
||||||
|
action: string,
|
||||||
|
targetId: string,
|
||||||
|
details: Record<string, unknown>,
|
||||||
|
): DevAuditLog {
|
||||||
|
return {
|
||||||
|
event_id: eventId,
|
||||||
|
timestamp,
|
||||||
|
user_id: "actor-1",
|
||||||
|
event_type: "AUDIT",
|
||||||
|
status: "success",
|
||||||
|
ip_address: "127.0.0.1",
|
||||||
|
user_agent: "vitest",
|
||||||
|
details: JSON.stringify({
|
||||||
|
action,
|
||||||
|
target_id: targetId,
|
||||||
|
...details,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("recent client changes", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
window.localStorage.clear();
|
||||||
|
window.history.replaceState({}, "", "/");
|
||||||
|
});
|
||||||
|
|
||||||
|
function mockLocale(locale: "ko" | "en") {
|
||||||
|
window.localStorage.clear();
|
||||||
|
window.history.replaceState({}, "", `/${locale}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
it("translates action labels and relation details by locale", () => {
|
||||||
|
mockLocale("en");
|
||||||
|
|
||||||
|
expect(getRecentClientActionLabel("CREATE_CLIENT")).toBe("App creation");
|
||||||
|
expect(getRecentClientActionLabel("UPDATE_CLIENT")).toBe("Settings changes");
|
||||||
|
expect(getRecentClientActionLabel("UPDATE_CLIENT_STATUS")).toBe(
|
||||||
|
"Status changes",
|
||||||
|
);
|
||||||
|
expect(getRecentClientActionLabel("ROTATE_SECRET")).toBe(
|
||||||
|
"Client secret rotation",
|
||||||
|
);
|
||||||
|
expect(getRecentClientActionLabel("ADD_RELATION")).toBe("Add Relationship");
|
||||||
|
expect(getRecentClientActionLabel("REMOVE_RELATION")).toBe("Remove");
|
||||||
|
expect(getRecentClientActionLabel("DELETE_CLIENT")).toBe("App deletion");
|
||||||
|
expect(getRecentClientActionLabel("OTHER_ACTION")).toBe("OTHER_ACTION");
|
||||||
|
|
||||||
|
expect(
|
||||||
|
buildRecentClientChangeDetails("ROTATE_SECRET", {
|
||||||
|
after: {},
|
||||||
|
}),
|
||||||
|
).toEqual([{ label: "Client Secret", value: "Secret Rotated" }]);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
buildRecentClientChangeDetails("ADD_RELATION", {
|
||||||
|
after: {
|
||||||
|
relation: "admins",
|
||||||
|
subject: "User:1",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).toEqual([
|
||||||
|
{ label: "Relation", value: "admins" },
|
||||||
|
{ label: "Subject", value: "User:1" },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("builds recent client changes with sorting, filtering, and detail slicing", () => {
|
||||||
|
mockLocale("ko");
|
||||||
|
|
||||||
|
const clients = [makeClient("client-a", "Alpha"), makeClient("client-b", "")];
|
||||||
|
const auditLogs = [
|
||||||
|
makeAuditLog("evt-1", "2026-05-27T07:00:00.000Z", "CREATE_CLIENT", "client-a", {
|
||||||
|
after: { name: "Alpha", type: "private", status: "active" },
|
||||||
|
}),
|
||||||
|
makeAuditLog("evt-2", "2026-05-27T08:00:00.000Z", "UPDATE_CLIENT", "client-a", {
|
||||||
|
before: {
|
||||||
|
name: "Alpha old",
|
||||||
|
status: "inactive",
|
||||||
|
sameField: "same",
|
||||||
|
oldField: "old-value",
|
||||||
|
},
|
||||||
|
after: {
|
||||||
|
name: "Alpha new",
|
||||||
|
status: "active",
|
||||||
|
sameField: "same",
|
||||||
|
newField: "new-value",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
makeAuditLog("evt-3", "2026-05-27T09:00:00.000Z", "UPDATE_CLIENT_STATUS", "client-a", {
|
||||||
|
before: { status: "inactive" },
|
||||||
|
after: { status: "active" },
|
||||||
|
}),
|
||||||
|
makeAuditLog("evt-4", "2026-05-27T10:00:00.000Z", "ADD_RELATION", "client-b", {
|
||||||
|
after: {
|
||||||
|
relation: "audit_viewer",
|
||||||
|
subject: "User:89692983-f512-4d96-845d-ac6123d08b95",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
makeAuditLog("evt-5", "2026-05-27T11:00:00.000Z", "REMOVE_RELATION", "client-b", {
|
||||||
|
before: {
|
||||||
|
relation: "admins",
|
||||||
|
subject: "User:89692983-f512-4d96-845d-ac6123d08b95",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
makeAuditLog("evt-6", "2026-05-27T12:00:00.000Z", "ROTATE_SECRET", "client-a", {
|
||||||
|
after: {},
|
||||||
|
}),
|
||||||
|
makeAuditLog("evt-7", "2026-05-27T13:00:00.000Z", "DELETE_CLIENT", "client-a", {
|
||||||
|
before: {
|
||||||
|
name: "Alpha",
|
||||||
|
status: "inactive",
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
makeAuditLog("evt-8", "2026-05-27T14:00:00.000Z", "UNSUPPORTED_ACTION", "client-a", {
|
||||||
|
after: { name: "Ignored" },
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
|
const changes = buildRecentClientChanges(
|
||||||
|
auditLogs,
|
||||||
|
clients,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(changes).toHaveLength(7);
|
||||||
|
expect(changes[0]).toMatchObject({
|
||||||
|
eventId: "evt-7",
|
||||||
|
clientName: "Alpha",
|
||||||
|
actionLabel: "앱 삭제",
|
||||||
|
});
|
||||||
|
expect(changes[1]).toMatchObject({
|
||||||
|
eventId: "evt-6",
|
||||||
|
clientName: "Alpha",
|
||||||
|
actionLabel: "클라이언트 시크릿 재발급",
|
||||||
|
detailLabels: [
|
||||||
|
{
|
||||||
|
label: "클라이언트 시크릿",
|
||||||
|
value: "Client Secret이 재발급되었습니다.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
expect(changes[2]).toMatchObject({
|
||||||
|
eventId: "evt-5",
|
||||||
|
clientName: "client-b",
|
||||||
|
actionLabel: "제외",
|
||||||
|
detailLabels: [
|
||||||
|
{ label: "관계", value: "admins" },
|
||||||
|
{
|
||||||
|
label: "주체",
|
||||||
|
value: "User:89692983-f512-4d96-845d-ac6123d08b95",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
expect(changes[4]).toMatchObject({
|
||||||
|
eventId: "evt-3",
|
||||||
|
actionLabel: "상태 변경",
|
||||||
|
clientName: "Alpha",
|
||||||
|
detailLabels: [{ value: "inactive → active" }],
|
||||||
|
});
|
||||||
|
expect(changes[5]).toMatchObject({
|
||||||
|
eventId: "evt-2",
|
||||||
|
actionLabel: "설정 변경",
|
||||||
|
detailLabels: [
|
||||||
|
{ label: "애플리케이션", value: "Alpha old → Alpha new" },
|
||||||
|
{ label: "상태", value: "inactive → active" },
|
||||||
|
{ label: "oldField", value: "old-value" },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
expect(changes[6]).toMatchObject({
|
||||||
|
eventId: "evt-1",
|
||||||
|
actionLabel: "앱 생성",
|
||||||
|
detailLabels: [
|
||||||
|
{ label: "애플리케이션", value: "Alpha" },
|
||||||
|
{ label: "유형", value: "private" },
|
||||||
|
{ label: "상태", value: "active" },
|
||||||
|
],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -59,6 +59,12 @@ export function getRecentClientActionLabel(action: string) {
|
|||||||
|
|
||||||
function getRecentClientFieldLabel(key: string) {
|
function getRecentClientFieldLabel(key: string) {
|
||||||
switch (key) {
|
switch (key) {
|
||||||
|
case "name":
|
||||||
|
return t("ui.dev.clients.table.application", "Application");
|
||||||
|
case "type":
|
||||||
|
return t("ui.dev.clients.table.type", "Type");
|
||||||
|
case "status":
|
||||||
|
return t("ui.dev.clients.table.status", "Status");
|
||||||
case "relation":
|
case "relation":
|
||||||
return t("ui.dev.clients.relationships.relation", "관계");
|
return t("ui.dev.clients.relationships.relation", "관계");
|
||||||
case "subject":
|
case "subject":
|
||||||
@@ -84,7 +90,7 @@ export function buildRecentClientChangeDetails(
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
label: getRecentClientFieldLabel("client_secret"),
|
label: getRecentClientFieldLabel("client_secret"),
|
||||||
value: t("msg.dev.clients.secret_rotated", "재발급"),
|
value: t("msg.dev.clients.details.secret_rotated", "재발급"),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user