forked from baron/baron-sso
devfront: 개요 페이지 경로와 레이아웃 정리
This commit is contained in:
@@ -9,7 +9,7 @@ import ClientDetailsPage from "../features/clients/ClientDetailsPage";
|
|||||||
import ClientGeneralPage from "../features/clients/ClientGeneralPage";
|
import ClientGeneralPage from "../features/clients/ClientGeneralPage";
|
||||||
import ClientRelationsPage from "../features/clients/ClientRelationsPage";
|
import ClientRelationsPage from "../features/clients/ClientRelationsPage";
|
||||||
import ClientsPage from "../features/clients/ClientsPage";
|
import ClientsPage from "../features/clients/ClientsPage";
|
||||||
import DashboardPage from "../features/dashboard/DashboardPage";
|
import GlobalOverviewPage from "../features/overview/GlobalOverviewPage";
|
||||||
import DeveloperRequestPage from "../features/developer-request/DeveloperRequestPage";
|
import DeveloperRequestPage from "../features/developer-request/DeveloperRequestPage";
|
||||||
import ProfilePage from "../features/profile/ProfilePage";
|
import ProfilePage from "../features/profile/ProfilePage";
|
||||||
import { DEVFRONT_AUTH_CALLBACK_PATH } from "../lib/authConfig";
|
import { DEVFRONT_AUTH_CALLBACK_PATH } from "../lib/authConfig";
|
||||||
@@ -30,7 +30,7 @@ export const devFrontRoutes: RouteObject[] = [
|
|||||||
{
|
{
|
||||||
element: <AppLayout />,
|
element: <AppLayout />,
|
||||||
children: [
|
children: [
|
||||||
{ index: true, element: <DashboardPage /> },
|
{ index: true, element: <GlobalOverviewPage /> },
|
||||||
{ path: "clients", element: <ClientsPage /> },
|
{ path: "clients", element: <ClientsPage /> },
|
||||||
{ path: "clients/new", element: <ClientGeneralPage /> },
|
{ path: "clients/new", element: <ClientGeneralPage /> },
|
||||||
{ path: "clients/:id", element: <ClientDetailsPage /> },
|
{ path: "clients/:id", element: <ClientDetailsPage /> },
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
Layers3,
|
Layers3,
|
||||||
ShieldCheck,
|
ShieldCheck,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { type ReactNode, useMemo, useState } from "react";
|
import { useMemo, useState } from "react";
|
||||||
import { useAuth } from "react-oidc-context";
|
import { useAuth } from "react-oidc-context";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import {
|
import {
|
||||||
@@ -22,6 +22,11 @@ import {
|
|||||||
} from "../../lib/devApi";
|
} from "../../lib/devApi";
|
||||||
import { t } from "../../lib/i18n";
|
import { t } from "../../lib/i18n";
|
||||||
import { resolveProfileRole } from "../../lib/role";
|
import { resolveProfileRole } from "../../lib/role";
|
||||||
|
import {
|
||||||
|
OverviewAxisNotes,
|
||||||
|
OverviewMetric,
|
||||||
|
OverviewSelectionChips,
|
||||||
|
} from "../../../../common/core/components/overview";
|
||||||
|
|
||||||
type ClientDistribution = {
|
type ClientDistribution = {
|
||||||
activeClients: number;
|
activeClients: number;
|
||||||
@@ -261,24 +266,6 @@ function formatMetric(value: number | undefined) {
|
|||||||
return value === undefined ? "-" : value.toLocaleString();
|
return value === undefined ? "-" : value.toLocaleString();
|
||||||
}
|
}
|
||||||
|
|
||||||
function OverviewMetric({
|
|
||||||
icon,
|
|
||||||
label,
|
|
||||||
value,
|
|
||||||
}: {
|
|
||||||
icon: ReactNode;
|
|
||||||
label: string;
|
|
||||||
value: string;
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<span className="inline-flex items-center gap-2 whitespace-nowrap text-sm">
|
|
||||||
<span className="text-muted-foreground">{icon}</span>
|
|
||||||
<span className="text-muted-foreground">{label}</span>
|
|
||||||
<span className="font-semibold tabular-nums">{value}</span>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function RPUsageMixedChart({
|
function RPUsageMixedChart({
|
||||||
period,
|
period,
|
||||||
rows,
|
rows,
|
||||||
@@ -425,10 +412,10 @@ function RPUsageMixedChart({
|
|||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-wrap gap-x-4 gap-y-1 text-xs text-muted-foreground">
|
<OverviewAxisNotes
|
||||||
<span>{t("ui.dev.dashboard.chart.x_axis", "X축: 기간")}</span>
|
xAxisLabel={t("ui.common.chart.axis.x", "X축: 기간")}
|
||||||
<span>{t("ui.dev.dashboard.chart.y_axis", "Y축: 로그인 요청 수")}</span>
|
yAxisLabel={t("ui.common.chart.axis.y", "Y축: 로그인 요청 수")}
|
||||||
</div>
|
/>
|
||||||
|
|
||||||
{multiLinePoints && multiLinePoints.length > 0 ? (
|
{multiLinePoints && multiLinePoints.length > 0 ? (
|
||||||
<div className="grid gap-x-6 gap-y-2 border-t border-border/60 pt-2 text-xs md:grid-cols-2 xl:grid-cols-3">
|
<div className="grid gap-x-6 gap-y-2 border-t border-border/60 pt-2 text-xs md:grid-cols-2 xl:grid-cols-3">
|
||||||
@@ -486,7 +473,7 @@ function RPUsageMixedChart({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DashboardPage() {
|
function GlobalOverviewPage() {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const auth = useAuth();
|
const auth = useAuth();
|
||||||
const hasAccessToken = Boolean(auth.user?.access_token);
|
const hasAccessToken = Boolean(auth.user?.access_token);
|
||||||
@@ -633,7 +620,7 @@ function DashboardPage() {
|
|||||||
<div className="rounded-xl border border-border/60 bg-card p-8 text-center">
|
<div className="rounded-xl border border-border/60 bg-card p-8 text-center">
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
<h2 className="text-2xl font-semibold tracking-tight">
|
<h2 className="text-2xl font-semibold tracking-tight">
|
||||||
{t("ui.dev.dashboard.title", "대시보드")}
|
{t("ui.common.overview.title", "운영 현황")}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="font-medium text-foreground">
|
<p className="font-medium text-foreground">
|
||||||
{isDeveloperRequestPending
|
{isDeveloperRequestPending
|
||||||
@@ -678,7 +665,7 @@ function DashboardPage() {
|
|||||||
<div className="flex flex-wrap items-end justify-between gap-4">
|
<div className="flex flex-wrap items-end justify-between gap-4">
|
||||||
<div className="space-y-1">
|
<div className="space-y-1">
|
||||||
<h2 className="text-2xl font-semibold tracking-tight">
|
<h2 className="text-2xl font-semibold tracking-tight">
|
||||||
{t("ui.dev.dashboard.title", "Dashboard")}
|
{t("ui.common.overview.title", "운영 현황")}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
{t(
|
{t(
|
||||||
@@ -736,9 +723,9 @@ function DashboardPage() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex h-8 items-center gap-1" aria-label="집계 단위">
|
<div className="flex h-8 items-center gap-1" aria-label="집계 단위">
|
||||||
{[
|
{[
|
||||||
["day", t("ui.dev.dashboard.chart.period_day", "일")],
|
["day", t("ui.common.chart.period.day", "일")],
|
||||||
["week", t("ui.dev.dashboard.chart.period_week", "주")],
|
["week", t("ui.common.chart.period.week", "주")],
|
||||||
["month", t("ui.dev.dashboard.chart.period_month", "월")],
|
["month", t("ui.common.chart.period.month", "월")],
|
||||||
].map(([value, label]) => (
|
].map(([value, label]) => (
|
||||||
<button
|
<button
|
||||||
key={value}
|
key={value}
|
||||||
@@ -757,31 +744,13 @@ function DashboardPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-wrap gap-2 rounded-xl border border-border/60 bg-card/60 p-3">
|
<OverviewSelectionChips
|
||||||
<label className="inline-flex items-center gap-2 rounded-full border border-border/60 px-3 py-1.5 text-xs">
|
allLabel={t("ui.dev.dashboard.chart.filter_all", "전체")}
|
||||||
<input
|
options={clientFilterOptions}
|
||||||
type="checkbox"
|
selectedIds={selectedClientIds}
|
||||||
checked={isAllClientsSelected}
|
onSelectAll={selectAllClients}
|
||||||
onChange={selectAllClients}
|
onToggle={toggleClientSelection}
|
||||||
className="h-3.5 w-3.5"
|
/>
|
||||||
/>
|
|
||||||
<span>{t("ui.dev.dashboard.chart.filter_all", "전체")}</span>
|
|
||||||
</label>
|
|
||||||
{clientFilterOptions.map((client) => (
|
|
||||||
<label
|
|
||||||
key={client.id}
|
|
||||||
className="inline-flex items-center gap-2 rounded-full border border-border/60 px-3 py-1.5 text-xs"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
checked={selectedClientIds.includes(client.id)}
|
|
||||||
onChange={() => toggleClientSelection(client.id)}
|
|
||||||
className="h-3.5 w-3.5"
|
|
||||||
/>
|
|
||||||
<span>{client.label}</span>
|
|
||||||
</label>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{usageQuery.isError ? (
|
{usageQuery.isError ? (
|
||||||
<div className="text-sm text-muted-foreground">{usageErrorText}</div>
|
<div className="text-sm text-muted-foreground">{usageErrorText}</div>
|
||||||
@@ -910,4 +879,4 @@ function DashboardPage() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DashboardPage;
|
export default GlobalOverviewPage;
|
||||||
@@ -967,7 +967,6 @@ start_import = "Start Import"
|
|||||||
|
|
||||||
[ui.admin.overview]
|
[ui.admin.overview]
|
||||||
kicker = "Global Overview"
|
kicker = "Global Overview"
|
||||||
title = "Tenant-independent control plane"
|
|
||||||
|
|
||||||
[ui.admin.overview.playbook]
|
[ui.admin.overview.playbook]
|
||||||
title = "Admin playbook"
|
title = "Admin playbook"
|
||||||
@@ -1658,7 +1657,6 @@ private_headless = "Server side App (Headless Login)"
|
|||||||
|
|
||||||
[ui.dev.dashboard]
|
[ui.dev.dashboard]
|
||||||
ready_badge = "devfront ready"
|
ready_badge = "devfront ready"
|
||||||
title = "Dashboard"
|
|
||||||
|
|
||||||
[ui.dev.dashboard.badge]
|
[ui.dev.dashboard.badge]
|
||||||
consent_guard = "Consent guard ready"
|
consent_guard = "Consent guard ready"
|
||||||
@@ -1676,9 +1674,6 @@ title = "Application Distribution"
|
|||||||
[ui.dev.dashboard.chart]
|
[ui.dev.dashboard.chart]
|
||||||
aria = "RP request overview"
|
aria = "RP request overview"
|
||||||
filter_all = "All"
|
filter_all = "All"
|
||||||
period_day = "Day"
|
|
||||||
period_month = "Month"
|
|
||||||
period_week = "Week"
|
|
||||||
series = "Login {{login}} / Users {{subjects}}"
|
series = "Login {{login}} / Users {{subjects}}"
|
||||||
title = "Login requests by application"
|
title = "Login requests by application"
|
||||||
x_axis = "X-axis: Period"
|
x_axis = "X-axis: Period"
|
||||||
|
|||||||
@@ -967,7 +967,6 @@ start_import = "임포트 시작"
|
|||||||
|
|
||||||
[ui.admin.overview]
|
[ui.admin.overview]
|
||||||
kicker = "Global Overview"
|
kicker = "Global Overview"
|
||||||
title = "Tenant-independent control plane"
|
|
||||||
|
|
||||||
[ui.admin.overview.playbook]
|
[ui.admin.overview.playbook]
|
||||||
title = "Admin playbook"
|
title = "Admin playbook"
|
||||||
@@ -1657,7 +1656,6 @@ private_headless = "Server side App (Headless Login)"
|
|||||||
|
|
||||||
[ui.dev.dashboard]
|
[ui.dev.dashboard]
|
||||||
ready_badge = "devfront ready"
|
ready_badge = "devfront ready"
|
||||||
title = "대시보드"
|
|
||||||
|
|
||||||
[ui.dev.dashboard.badge]
|
[ui.dev.dashboard.badge]
|
||||||
consent_guard = "Consent guard ready"
|
consent_guard = "Consent guard ready"
|
||||||
@@ -1675,9 +1673,6 @@ title = "애플리케이션 구성 요약"
|
|||||||
[ui.dev.dashboard.chart]
|
[ui.dev.dashboard.chart]
|
||||||
aria = "RP 요청 현황"
|
aria = "RP 요청 현황"
|
||||||
filter_all = "전체"
|
filter_all = "전체"
|
||||||
period_day = "일"
|
|
||||||
period_month = "월"
|
|
||||||
period_week = "주"
|
|
||||||
series = "로그인 {{login}} / 사용자 {{subjects}}"
|
series = "로그인 {{login}} / 사용자 {{subjects}}"
|
||||||
title = "애플리케이션별 로그인 요청 현황"
|
title = "애플리케이션별 로그인 요청 현황"
|
||||||
x_axis = "X축: 기간"
|
x_axis = "X축: 기간"
|
||||||
|
|||||||
@@ -1006,7 +1006,6 @@ start_import = ""
|
|||||||
|
|
||||||
[ui.admin.overview]
|
[ui.admin.overview]
|
||||||
kicker = ""
|
kicker = ""
|
||||||
title = ""
|
|
||||||
|
|
||||||
[ui.admin.overview.playbook]
|
[ui.admin.overview.playbook]
|
||||||
title = ""
|
title = ""
|
||||||
@@ -1714,7 +1713,6 @@ private_headless = ""
|
|||||||
|
|
||||||
[ui.dev.dashboard]
|
[ui.dev.dashboard]
|
||||||
ready_badge = ""
|
ready_badge = ""
|
||||||
title = ""
|
|
||||||
|
|
||||||
[ui.dev.dashboard.badge]
|
[ui.dev.dashboard.badge]
|
||||||
consent_guard = ""
|
consent_guard = ""
|
||||||
@@ -1732,9 +1730,6 @@ title = ""
|
|||||||
[ui.dev.dashboard.chart]
|
[ui.dev.dashboard.chart]
|
||||||
aria = ""
|
aria = ""
|
||||||
filter_all = ""
|
filter_all = ""
|
||||||
period_day = ""
|
|
||||||
period_month = ""
|
|
||||||
period_week = ""
|
|
||||||
series = ""
|
series = ""
|
||||||
title = ""
|
title = ""
|
||||||
x_axis = ""
|
x_axis = ""
|
||||||
|
|||||||
Reference in New Issue
Block a user