1
0
forked from baron/baron-sso

feat: enhance tenant admin experience with form locking and column visibility settings

This commit is contained in:
2026-03-04 13:55:54 +09:00
parent 88720b48c4
commit 2b4b40c0d9
3 changed files with 105 additions and 6 deletions

View File

@@ -7,6 +7,7 @@ import {
Plus,
RefreshCw,
Search,
Settings2,
Trash2,
User,
} from "lucide-react";
@@ -21,6 +22,15 @@ import {
CardHeader,
CardTitle,
} from "../../components/ui/card";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "../../components/ui/dialog";
import { Input } from "../../components/ui/input";
import {
Table,
@@ -52,6 +62,7 @@ function UserListPage() {
const [search, setSearch] = React.useState("");
const [searchDraft, setSearchDraft] = React.useState("");
const [selectedCompany, setSelectedCompany] = React.useState<string>("");
const [visibleColumns, setVisibleColumns] = React.useState<Record<string, boolean>>({});
const limit = 50;
const offset = (page - 1) * limit;
@@ -89,6 +100,28 @@ function UserListPage() {
? (tenantDetail?.config?.userSchema as UserSchemaField[])
: [];
// Initialize visible columns when schema changes
React.useEffect(() => {
if (userSchema.length > 0) {
const initial: Record<string, boolean> = {};
for (const field of userSchema) {
initial[field.key] = true;
}
setVisibleColumns((prev) => {
// Only set if not already set for these keys to avoid reset on every render
const next = { ...initial, ...prev };
return next;
});
}
}, [userSchema]);
const toggleColumn = (key: string) => {
setVisibleColumns((prev) => ({
...prev,
[key]: !prev[key],
}));
};
const query = useQuery({
queryKey: ["users", { limit, offset, search, companyCode: selectedCompany }],
queryFn: () => fetchUsers(limit, offset, search, selectedCompany),
@@ -173,6 +206,47 @@ function UserListPage() {
{t("ui.common.refresh", "새로고침")}
</Button>
<UserBulkUploadModal onSuccess={() => query.refetch()} />
<Dialog>
<DialogTrigger asChild>
<Button variant="outline" size="icon">
<Settings2 size={16} />
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>{t("ui.admin.users.list.columns.title", "표시 컬럼 설정")}</DialogTitle>
<DialogDescription>
{t("msg.admin.users.list.columns.description", "사용자 목록에 표시할 커스텀 필드를 선택하세요.")}
</DialogDescription>
</DialogHeader>
<div className="grid gap-4 py-4">
{userSchema.length === 0 && (
<p className="text-sm text-muted-foreground text-center py-4">
{t("msg.admin.users.list.columns.no_custom", "현재 테넌트에 정의된 커스텀 필드가 없습니다.")}
</p>
)}
{userSchema.map((field) => (
<label key={field.key} className="flex items-center gap-3 p-2 rounded-lg hover:bg-muted/50 cursor-pointer">
<input
type="checkbox"
className="w-4 h-4 rounded border-gray-300 text-primary focus:ring-primary"
checked={visibleColumns[field.key] !== false}
onChange={() => toggleColumn(field.key)}
/>
<div className="flex flex-col">
<span className="text-sm font-medium">{field.label}</span>
<span className="text-xs text-muted-foreground font-mono">{field.key}</span>
</div>
</label>
))}
</div>
<DialogFooter>
<DialogTrigger asChild>
<Button variant="secondary">{t("ui.common.close", "닫기")}</Button>
</DialogTrigger>
</DialogFooter>
</DialogContent>
</Dialog>
<Button asChild>
<Link to="/users/new">
<Plus size={16} />
@@ -267,9 +341,11 @@ function UserListPage() {
</TableHead>
{/* Dynamic Columns from Schema */}
{userSchema.map((field) => (
<TableHead key={field.key} className="uppercase">
{field.label}
</TableHead>
visibleColumns[field.key] !== false && (
<TableHead key={field.key} className="uppercase">
{field.label}
</TableHead>
)
))}
<TableHead>
{t("ui.admin.users.list.table.created", "CREATED")}
@@ -341,9 +417,11 @@ function UserListPage() {
</TableCell>
{/* Dynamic Metadata Cells */}
{userSchema.map((field) => (
<TableCell key={field.key} className="text-sm">
{String(user.metadata?.[field.key] ?? "-")}
</TableCell>
visibleColumns[field.key] !== false && (
<TableCell key={field.key} className="text-sm">
{String(user.metadata?.[field.key] ?? "-")}
</TableCell>
)
))}
<TableCell className="text-sm text-muted-foreground">
{new Date(user.createdAt).toLocaleDateString()}