forked from baron/baron-sso
dev 병합 code-check 오류 수정
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 = ""
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 = ""
|
||||
|
||||
Reference in New Issue
Block a user