1
0
forked from baron/baron-sso

dev 병합 code-check 오류 수정

This commit is contained in:
2026-05-08 15:04:40 +09:00
parent 59cb482219
commit e78b2bea50
8 changed files with 144 additions and 28 deletions

View File

@@ -123,6 +123,7 @@ function createEmptyAppointment(): AppointmentDraft {
tenantId: "",
tenantName: "",
tenantSlug: "",
isPrimary: false,
isOwner: false,
jobTitle: "",
position: "",
@@ -554,6 +555,15 @@ function UserDetailPage() {
);
};
const setPrimaryAppointment = (targetIndex: number) => {
setAdditionalAppointments((current) =>
current.map((appointment, index) => ({
...appointment,
isPrimary: index === targetIndex,
})),
);
};
const handleUserTypeChange = (value: string) => {
const nextType = value as UserType;
setUserType(nextType);
@@ -645,6 +655,9 @@ function UserDetailPage() {
Array.isArray(rawAppointments)
? (rawAppointments as UserAppointment[]).map((appointment) => ({
...appointment,
isPrimary:
appointment.isPrimary === true ||
appointment.tenantId === primaryFromMetadata?.id,
draftId: createDraftId(),
}))
: isUserHanmacFamily
@@ -654,6 +667,7 @@ function UserDetailPage() {
tenantId: tenant.id,
tenantName: tenant.name,
tenantSlug: tenant.slug,
isPrimary: tenant.id === fallbackAppointment?.id,
isOwner:
metadata.primaryTenantIsOwner === true &&
tenant.id === fallbackAppointment?.id,
@@ -667,6 +681,7 @@ function UserDetailPage() {
tenantId: fallbackAppointment.id,
tenantName: fallbackAppointment.name,
tenantSlug: fallbackAppointment.slug,
isPrimary: true,
isOwner: metadata.primaryTenantIsOwner === true,
jobTitle: user.jobTitle,
position: user.position,
@@ -781,7 +796,15 @@ function UserDetailPage() {
payload.metadata = {
...metadata,
additionalAppointments: appointments,
primaryTenantId: primaryAppointment?.tenantId,
primaryTenantName: primaryAppointment?.tenantName,
primaryTenantSlug: primaryAppointment?.tenantSlug,
primaryTenantIsOwner: primaryAppointment?.isOwner ?? false,
};
payload.tenantSlug = primaryAppointment?.tenantSlug;
payload.primaryTenantId = primaryAppointment?.tenantId;
payload.primaryTenantName = primaryAppointment?.tenantName;
payload.primaryTenantIsOwner = primaryAppointment?.isOwner ?? false;
}
mutation.mutate(payload);

View File

@@ -33,7 +33,13 @@ import {
DialogTrigger,
} from "../../components/ui/dialog";
import { Input } from "../../components/ui/input";
import { Switch } from "../../components/ui/switch";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "../../components/ui/select";
import {
Table,
TableBody,
@@ -547,7 +553,7 @@ function UserListPage() {
/>
</TableHead>
<TableHead
className="min-w-[220px] cursor-pointer hover:bg-muted/50 transition-colors"
className="min-w-[220px] whitespace-nowrap cursor-pointer hover:bg-muted/50 transition-colors"
onClick={() => requestSort("id")}
>
<div className="flex items-center">
@@ -556,7 +562,7 @@ function UserListPage() {
</div>
</TableHead>
<TableHead
className="min-w-[200px] cursor-pointer hover:bg-muted/50 transition-colors"
className="min-w-[200px] whitespace-nowrap cursor-pointer hover:bg-muted/50 transition-colors"
onClick={() => requestSort("name_email")}
>
<div className="flex items-center">
@@ -568,7 +574,7 @@ function UserListPage() {
</div>
</TableHead>
<TableHead
className="cursor-pointer hover:bg-muted/50 transition-colors"
className="whitespace-nowrap cursor-pointer hover:bg-muted/50 transition-colors"
onClick={() => requestSort("status")}
>
<div className="flex items-center">
@@ -577,7 +583,7 @@ function UserListPage() {
</div>
</TableHead>
<TableHead
className="cursor-pointer hover:bg-muted/50 transition-colors"
className="whitespace-nowrap cursor-pointer hover:bg-muted/50 transition-colors"
onClick={() => requestSort("tenant_dept")}
>
<div className="flex items-center">
@@ -594,7 +600,7 @@ function UserListPage() {
visibleColumns[field.key] !== false && (
<TableHead
key={field.key}
className="uppercase cursor-pointer hover:bg-muted/50 transition-colors"
className="whitespace-nowrap uppercase cursor-pointer hover:bg-muted/50 transition-colors"
onClick={() => requestSort(field.key)}
>
<div className="flex items-center">
@@ -605,7 +611,7 @@ function UserListPage() {
),
)}
<TableHead
className="cursor-pointer hover:bg-muted/50 transition-colors"
className="whitespace-nowrap cursor-pointer hover:bg-muted/50 transition-colors"
onClick={() => requestSort("createdAt")}
>
<div className="flex items-center">
@@ -693,28 +699,42 @@ function UserListPage() {
)}
</div>
</div>
</TableCell>{" "}
</TableCell>
<TableCell>
<div className="flex items-center gap-2">
<Switch
checked={user.status === "active"}
onCheckedChange={(checked) =>
<Select
value={user.status}
onValueChange={(value: "active" | "inactive") =>
statusMutation.mutate({
userId: user.id,
status: checked ? "active" : "inactive",
status: value,
})
}
disabled={
statusMutation.isPending ||
user.id === profile?.id
}
aria-label={t(
"ui.admin.users.list.toggle_status",
"{{name}} 활성 상태",
{ name: user.name },
)}
data-testid={`user-status-toggle-${user.id}`}
/>
>
<SelectTrigger
className="h-8 w-[112px]"
aria-label={t(
"ui.admin.users.list.toggle_status",
"{{name}} 활성 상태",
{ name: user.name },
)}
data-testid={`user-status-select-${user.id}`}
>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="active">
{t("ui.common.status.active", "활성")}
</SelectItem>
<SelectItem value="inactive">
{t("ui.common.status.inactive", "비활성")}
</SelectItem>
</SelectContent>
</Select>
<span className="text-sm text-muted-foreground">
{t(`ui.common.status.${user.status}`, user.status)}
</span>

View File

@@ -131,12 +131,17 @@ empty = ""
import_error = ""
import_success = ""
loading = ""
no_results = ""
subtitle = ""
[msg.admin.groups.members]
add_modal_desc = ""
add_success = ""
all_added = ""
count = ""
empty = ""
move_modal_desc = ""
move_success = ""
remove_confirm = ""
remove_success = ""
title = ""
@@ -234,6 +239,9 @@ subtitle = ""
desc = ""
empty = ""
limit_notice = ""
remove_confirm = ""
remove_error = ""
remove_success = ""
[msg.admin.tenants.registry]
count = ""
@@ -250,6 +258,7 @@ empty = ""
subtitle = ""
[msg.admin.users]
confirm_remove_org = ""
export_error = ""
status_error = ""
@@ -827,8 +836,11 @@ unit_level_placeholder = ""
title = ""
[ui.admin.groups.members]
add_modal_title = ""
move_modal_title = ""
[ui.admin.groups.members.table]
actions = ""
email = ""
name = ""
remove = ""
@@ -985,8 +997,12 @@ search_placeholder = ""
select_placeholder = ""
[ui.admin.tenants.members]
add_existing = ""
create_new = ""
descendants = ""
direct = ""
remove = ""
view_profile = ""
[msg.admin.apikeys.registry]
count = ""
@@ -1013,6 +1029,7 @@ total = ""
total_label = ""
[ui.admin.tenants.members.table]
actions = ""
email = ""
name = ""
role = ""

View File

@@ -1,12 +1,6 @@
import { useMutation, useQuery } from "@tanstack/react-query";
import type { AxiosError } from "axios";
import {
BookOpenText,
Filter,
Plus,
Search,
X,
} from "lucide-react";
import { BookOpenText, Filter, Plus, Search, X } from "lucide-react";
import { useEffect, useState } from "react";
import { useAuth } from "react-oidc-context";
import { Link, useNavigate } from "react-router-dom";

View File

@@ -1,6 +1,10 @@
import { ServerCog, ShieldHalf } from "lucide-react";
import { useMemo, useState } from "react";
import { Avatar, AvatarFallback, AvatarImage } from "../../../components/ui/avatar";
import {
Avatar,
AvatarFallback,
AvatarImage,
} from "../../../components/ui/avatar";
import type { ClientSummary, ClientType } from "../../../lib/devApi";
import { t } from "../../../lib/i18n";
@@ -28,7 +32,10 @@ function TypeFallbackIcon({ type }: { type: ClientType }) {
export function ClientLogo({ client }: ClientLogoProps) {
const [didImageFail, setDidImageFail] = useState(false);
const logoUrl = useMemo(() => readLogoUrl(client.metadata), [client.metadata]);
const logoUrl = useMemo(
() => readLogoUrl(client.metadata),
[client.metadata],
);
const showImage = Boolean(logoUrl) && !didImageFail;
const clientName = client.name || t("ui.dev.clients.untitled", "Untitled");

View File

@@ -131,12 +131,17 @@ empty = "No organization units have been registered yet."
import_error = "Import Error"
import_success = "Import Success"
loading = "Loading..."
no_results = "No groups found."
subtitle = "Manage departments and teams under the current tenant."
[msg.admin.groups.members]
add_modal_desc = "Search and select members to add from users in this tenant."
add_success = "Member added successfully."
all_added = "All tenant members are already in this group."
count = "{{count}} members loaded."
empty = "No members are assigned to this organization unit."
move_modal_desc = "Select the target group to move the selected member."
move_success = "Member moved successfully."
remove_confirm = "Are you sure you want to remove this member?"
remove_success = "Member removed successfully."
title = "Member Management"
@@ -229,6 +234,9 @@ subtitle = "Set the basic tenant profile information."
desc = "View the list of users belonging to this organization."
empty = "No members found."
limit_notice = "Showing members from the first 10 descendant organizations due to size limits."
remove_confirm = "Are you sure you want to exclude '{{name}}' from this organization?"
remove_error = "An error occurred while excluding from organization."
remove_success = "Successfully excluded from organization."
[msg.admin.tenants.owners]
add_success = "Owner added successfully."
@@ -255,6 +263,7 @@ empty = "No child tenants are connected."
subtitle = "Review and manage child tenants linked under this tenant."
[msg.admin.users]
confirm_remove_org = "Do you want to remove this user from the organization?"
export_error = "Failed to export users."
status_error = "Failed to update user status."
@@ -1026,8 +1035,11 @@ unit_level_placeholder = "Unit Level Placeholder"
title = "User Groups"
[ui.admin.groups.members]
add_modal_title = "Add Member to Group"
move_modal_title = "Move Department"
[ui.admin.groups.members.table]
actions = "ACTIONS"
email = "Email"
name = "Name"
remove = "Remove"
@@ -1217,13 +1229,17 @@ self_delete_blocked = "You cannot delete your own account."
title = "API Key Registry"
[ui.admin.tenants.members]
add_existing = "Assign Existing Member"
create_new = "Create New Member"
delete_selected = "Delete Selected"
remove = "Exclude from Organization"
view_org_chart = "View Full Org Chart"
direct_label = "Direct"
list_title = "Member Management"
title = "Tenant Members ({{count}})"
total = "Total"
total_label = "Total"
view_profile = "View Profile"
[ui.admin.tenants.import_preview]
candidates = "Candidates"
@@ -1235,6 +1251,7 @@ no_candidates = "No matching tenants found."
title = "Import Preview"
[ui.admin.tenants.members.table]
actions = "ACTIONS"
email = "EMAIL"
name = "NAME"
role = "ROLE"

View File

@@ -612,12 +612,17 @@ empty = "테넌트에 등록된 조직 단위가 없습니다."
import_error = "가져오기 실패"
import_success = "조직도가 임포트되었습니다."
loading = "로딩 중..."
no_results = "그룹이 없습니다."
subtitle = "이 테넌트에 정의된 사용자 그룹 목록입니다."
[msg.admin.groups.members]
add_modal_desc = "이 테넌트에 속한 사용자 중 추가할 멤버를 검색하여 선택하세요."
add_success = "구성원이 추가되었습니다."
all_added = "모든 테넌트 멤버가 이미 이 그룹에 속해 있습니다."
count = "{{count}} 명"
empty = "멤버가 없습니다."
move_modal_desc = "선택한 멤버를 이동할 대상 그룹을 선택하세요."
move_success = "멤버가 이동되었습니다."
remove_confirm = "제거하시겠습니까?"
remove_success = "구성원이 제외되었습니다."
title = "[{{name}}] 멤버 관리"
@@ -710,6 +715,9 @@ subtitle = "필수 정보만 입력해도 생성 가능합니다. Slug는 없으
desc = "조직에 소속된 사용자 목록을 확인합니다."
empty = "소속된 사용자가 없습니다."
limit_notice = "하위 조직이 많아 상위 10개 조직의 멤버만 표시됩니다."
remove_confirm = "'{{name}}'님을 이 조직에서 제외하시겠습니까?"
remove_error = "조직에서 제외하는 중 오류가 발생했습니다."
remove_success = "조직에서 제외되었습니다."
[msg.admin.tenants.owners]
add_success = "소유자가 추가되었습니다."
@@ -736,6 +744,7 @@ empty = "하위 테넌트가 없습니다."
subtitle = "현재 테넌트 하위에 생성된 조직입니다."
[msg.admin.users]
confirm_remove_org = "이 조직에서 사용자를 제외하시겠습니까?"
export_error = "사용자 내보내기에 실패했습니다."
status_error = "사용자 상태 변경에 실패했습니다."
@@ -1505,8 +1514,11 @@ unit_level_placeholder = "예: 본부, 팀"
title = "User Groups"
[ui.admin.groups.members]
add_modal_title = "그룹에 멤버 추가"
move_modal_title = "부서 이동"
[ui.admin.groups.members.table]
actions = "ACTIONS"
email = "이메일"
name = "이름"
remove = "제거"
@@ -1679,13 +1691,17 @@ status_error = "사용자 상태 변경에 실패했습니다: {{error}}"
title = "API Key Registry"
[ui.admin.tenants.members]
add_existing = "기존 멤버 배정"
create_new = "신규 멤버 생성"
delete_selected = "선택 삭제"
remove = "조직에서 제외"
view_org_chart = "전체 조직도 보기"
direct_label = "직속"
list_title = "구성원 관리"
title = "테넌트 구성원 ({{count}})"
total = "전체"
total_label = "전체"
view_profile = "상세 정보"
[ui.admin.tenants.import_preview]
candidates = "후보"
@@ -1697,6 +1713,7 @@ no_candidates = "매칭 가능한 테넌트가 없습니다."
title = "임포트 미리보기"
[ui.admin.tenants.members.table]
actions = "ACTIONS"
email = "EMAIL"
name = "NAME"
role = "ROLE"

View File

@@ -481,12 +481,17 @@ empty = ""
import_error = ""
import_success = ""
loading = ""
no_results = ""
subtitle = ""
[msg.admin.groups.members]
add_modal_desc = ""
add_success = ""
all_added = ""
count = ""
empty = ""
move_modal_desc = ""
move_success = ""
remove_confirm = ""
remove_success = ""
title = ""
@@ -579,6 +584,9 @@ subtitle = ""
desc = ""
empty = ""
limit_notice = ""
remove_confirm = ""
remove_error = ""
remove_success = ""
[msg.admin.tenants.owners]
add_success = ""
@@ -605,6 +613,7 @@ empty = ""
subtitle = ""
[msg.admin.users]
confirm_remove_org = ""
export_error = ""
status_error = ""
@@ -1374,8 +1383,11 @@ unit_level_placeholder = ""
title = ""
[ui.admin.groups.members]
add_modal_title = ""
move_modal_title = ""
[ui.admin.groups.members.table]
actions = ""
email = ""
name = ""
remove = ""
@@ -1521,13 +1533,17 @@ search_placeholder = ""
select_placeholder = ""
[ui.admin.tenants.members]
add_existing = ""
create_new = ""
descendants = ""
direct = ""
direct_label = ""
list_title = ""
remove = ""
title = ""
total = ""
total_label = ""
view_profile = ""
[msg.admin.apikeys.registry]
count = ""
@@ -1554,15 +1570,20 @@ status_error = ""
title = ""
[ui.admin.tenants.members]
add_existing = ""
create_new = ""
delete_selected = ""
remove = ""
view_org_chart = ""
direct_label = ""
list_title = ""
title = ""
total = ""
total_label = ""
view_profile = ""
[ui.admin.tenants.members.table]
actions = ""
email = ""
name = ""
role = ""