forked from baron/baron-sso
조직도 줌 레벨 상향
This commit is contained in:
@@ -1,3 +1,6 @@
|
||||
{
|
||||
"extends": ["../common/config/biome.base.json"]
|
||||
"extends": ["../common/config/biome.base.json"],
|
||||
"files": {
|
||||
"ignore": [".vite"]
|
||||
}
|
||||
}
|
||||
|
||||
1068
orgfront/package-lock.json
generated
1068
orgfront/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,7 @@ import {
|
||||
Search,
|
||||
} from "lucide-react";
|
||||
import * as React from "react";
|
||||
import { SearchFilterBar } from "../../../../common/ui/search-filter-bar";
|
||||
import { ForbiddenMessage } from "../../components/common/ForbiddenMessage";
|
||||
import { Badge } from "../../components/ui/badge";
|
||||
import { Button } from "../../components/ui/button";
|
||||
@@ -28,7 +29,6 @@ import {
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "../../components/ui/table";
|
||||
import { SearchFilterBar } from "../../../../common/ui/search-filter-bar";
|
||||
import type { DevAuditLog } from "../../lib/devApi";
|
||||
import { fetchDevAuditLogs } from "../../lib/devApi";
|
||||
import { t } from "../../lib/i18n";
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
} from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { Link, useParams } from "react-router-dom";
|
||||
import { SearchFilterBar } from "../../../../common/ui/search-filter-bar";
|
||||
import { Badge } from "../../components/ui/badge";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import {
|
||||
@@ -26,7 +27,6 @@ import {
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "../../components/ui/table";
|
||||
import { SearchFilterBar } from "../../../../common/ui/search-filter-bar";
|
||||
import { fetchClient, fetchConsents, revokeConsent } from "../../lib/devApi";
|
||||
import { t } from "../../lib/i18n";
|
||||
import { cn } from "../../lib/utils";
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
import { useState } from "react";
|
||||
import { useAuth } from "react-oidc-context";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import { SearchFilterBar } from "../../../../common/ui/search-filter-bar";
|
||||
import { ForbiddenMessage } from "../../components/common/ForbiddenMessage";
|
||||
import {
|
||||
Avatar,
|
||||
@@ -36,7 +37,6 @@ import {
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "../../components/ui/table";
|
||||
import { SearchFilterBar } from "../../../../common/ui/search-filter-bar";
|
||||
import { fetchClients, fetchDevStats } from "../../lib/devApi";
|
||||
import { t } from "../../lib/i18n";
|
||||
import { cn } from "../../lib/utils";
|
||||
@@ -228,61 +228,59 @@ function ClientsPage() {
|
||||
}
|
||||
advancedOpen={isAdvancedFilterOpen}
|
||||
advanced={
|
||||
<>
|
||||
<div className="flex flex-wrap items-center gap-6">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs font-bold uppercase tracking-wider text-muted-foreground whitespace-nowrap">
|
||||
{t("ui.dev.clients.filter.type_label", "Type:")}
|
||||
</span>
|
||||
<select
|
||||
className="h-9 min-w-[140px] rounded-md border border-input bg-background px-3 text-sm focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary/30"
|
||||
value={typeFilter}
|
||||
onChange={(e) => setTypeFilter(e.target.value)}
|
||||
>
|
||||
<option value="all">
|
||||
{t("ui.dev.clients.filter.type_all", "모든 유형")}
|
||||
</option>
|
||||
<option value="private">
|
||||
{t("ui.dev.clients.type.private", "Server side App")}
|
||||
</option>
|
||||
<option value="pkce">
|
||||
{t("ui.dev.clients.type.pkce", "PKCE")}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs font-bold uppercase tracking-wider text-muted-foreground whitespace-nowrap">
|
||||
{t("ui.dev.clients.consents.status_label", "Status:")}
|
||||
</span>
|
||||
<select
|
||||
className="h-9 min-w-[140px] rounded-md border border-input bg-background px-3 text-sm focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary/30"
|
||||
value={statusFilter}
|
||||
onChange={(e) => setStatusFilter(e.target.value)}
|
||||
>
|
||||
<option value="all">
|
||||
{t("ui.dev.clients.filter.status_all", "모든 상태")}
|
||||
</option>
|
||||
<option value="active">
|
||||
{t("ui.common.status.active", "Active")}
|
||||
</option>
|
||||
<option value="inactive">
|
||||
{t("ui.common.status.inactive", "Inactive")}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="ml-auto text-xs text-muted-foreground"
|
||||
onClick={() => {
|
||||
setTypeFilter("all");
|
||||
setStatusFilter("all");
|
||||
}}
|
||||
<div className="flex flex-wrap items-center gap-6">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs font-bold uppercase tracking-wider text-muted-foreground whitespace-nowrap">
|
||||
{t("ui.dev.clients.filter.type_label", "Type:")}
|
||||
</span>
|
||||
<select
|
||||
className="h-9 min-w-[140px] rounded-md border border-input bg-background px-3 text-sm focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary/30"
|
||||
value={typeFilter}
|
||||
onChange={(e) => setTypeFilter(e.target.value)}
|
||||
>
|
||||
{t("ui.common.reset", "초기화")}
|
||||
</Button>
|
||||
<option value="all">
|
||||
{t("ui.dev.clients.filter.type_all", "모든 유형")}
|
||||
</option>
|
||||
<option value="private">
|
||||
{t("ui.dev.clients.type.private", "Server side App")}
|
||||
</option>
|
||||
<option value="pkce">
|
||||
{t("ui.dev.clients.type.pkce", "PKCE")}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs font-bold uppercase tracking-wider text-muted-foreground whitespace-nowrap">
|
||||
{t("ui.dev.clients.consents.status_label", "Status:")}
|
||||
</span>
|
||||
<select
|
||||
className="h-9 min-w-[140px] rounded-md border border-input bg-background px-3 text-sm focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary/30"
|
||||
value={statusFilter}
|
||||
onChange={(e) => setStatusFilter(e.target.value)}
|
||||
>
|
||||
<option value="all">
|
||||
{t("ui.dev.clients.filter.status_all", "모든 상태")}
|
||||
</option>
|
||||
<option value="active">
|
||||
{t("ui.common.status.active", "Active")}
|
||||
</option>
|
||||
<option value="inactive">
|
||||
{t("ui.common.status.inactive", "Inactive")}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="ml-auto text-xs text-muted-foreground"
|
||||
onClick={() => {
|
||||
setTypeFilter("all");
|
||||
setStatusFilter("all");
|
||||
}}
|
||||
>
|
||||
{t("ui.common.reset", "초기화")}
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</CardHeader>
|
||||
|
||||
@@ -345,7 +345,8 @@ describe("org chart layout", () => {
|
||||
|
||||
it("keeps zoom limits wide enough for large SVG organization charts", () => {
|
||||
expect(clampScale(0.08)).toBe(0.08);
|
||||
expect(clampScale(5)).toBe(5);
|
||||
expect(clampScale(32)).toBe(32);
|
||||
expect(clampScale(64)).toBe(32);
|
||||
});
|
||||
|
||||
it("switches semantic zoom modes from overview to detail", () => {
|
||||
|
||||
@@ -107,7 +107,7 @@ const WIDE_ASPECT_RATIO = MAX_TARGET_ASPECT_RATIO;
|
||||
const TALL_ASPECT_RATIO = 0.5;
|
||||
const CHART_MARGIN = 72;
|
||||
const MIN_SCALE = 0.08;
|
||||
const MAX_SCALE = 5;
|
||||
const MAX_SCALE = 32;
|
||||
const ZOOM_SENSITIVITY = 0.0015;
|
||||
const FAMILY_FILTER_ID = "hanmac-family";
|
||||
const DEFAULT_LAYOUT_OPTIONS: OrgChartLayoutOptions = {
|
||||
|
||||
@@ -14,7 +14,7 @@ const allowedHosts = getAllowedHosts(
|
||||
"127.0.0.1",
|
||||
],
|
||||
process.env.ORGFRONT_URL,
|
||||
process.env.ORGFRONT_ALLOWED_HOSTS
|
||||
process.env.ORGFRONT_ALLOWED_HOSTS,
|
||||
);
|
||||
|
||||
export default defineConfig(
|
||||
@@ -47,5 +47,5 @@ export default defineConfig(
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user