1
0
forked from baron/baron-sso
This commit is contained in:
2026-03-17 10:17:25 +09:00
parent f239ac984f
commit 8bc5b5a49b
7 changed files with 237 additions and 33 deletions

View File

@@ -477,8 +477,10 @@ function UserCreatePage() {
/>
{errors.metadata?.[field.key] && (
<p className="text-xs text-destructive">
{(errors.metadata[field.key] as { message?: string })
?.message}
{
(errors.metadata[field.key] as { message?: string })
?.message
}
</p>
)}
</div>

View File

@@ -45,7 +45,9 @@ type UserSchemaField = {
validation?: string;
};
type UserFormValues = UserUpdateRequest & { metadata: Record<string, Record<string, unknown>> };
type UserFormValues = UserUpdateRequest & {
metadata: Record<string, Record<string, unknown>>;
};
// [New] Component for per-tenant profile/schema management
function TenantProfileCard({

View File

@@ -13,25 +13,27 @@ export function parseUserCSV(text: string): BulkUserItem[] {
if (!lines[i].trim()) continue;
const values = lines[i].split(",").map((v) => v.trim());
const item: Record<string, any> = { metadata: {} };
const item: Partial<BulkUserItem> & { metadata: Record<string, string> } = {
metadata: {},
};
for (let index = 0; index < headers.length; index++) {
const header = headers[index];
const value = values[index];
if (value === undefined || value === "") continue;
if (
[
"email",
"name",
"phone",
"role",
"companycode",
"department",
].includes(header)
) {
const key = header === "companycode" ? "companyCode" : header;
item[key] = value;
if (header === "email") {
item.email = value;
} else if (header === "name") {
item.name = value;
} else if (header === "phone") {
item.phone = value;
} else if (header === "role") {
item.role = value;
} else if (header === "companycode") {
item.companyCode = value;
} else if (header === "department") {
item.department = value;
} else {
item.metadata[header] = value;
}

View File

@@ -116,6 +116,10 @@ count = "Count"
[msg.admin.groups]
[msg.admin.groups.create]
description = "Adds a new organization unit such as a department or team."
title = "Create New Organization Unit"
[msg.admin.groups.list]
create_error = "Create Failed"
create_success = "Create Success"
@@ -388,7 +392,7 @@ docs_body = "Includes PKCE, client_secret_basic, redirect URI validation tips."
subtitle = "Developer guides for Confidential/Public clients, redirect URIs, and auth methods."
[msg.dev.clients.registry]
description = "Description"
description = "OIDC 앱, 인증 방식, 리다이렉트 URI, 비밀키 재발행을 감사 로그와 함께 관리합니다."
[msg.dev.clients.scopes]
email = "Email"
@@ -588,15 +592,102 @@ organization = "Organization"
security = "Security"
[msg.userfront.qr]
rescan = "Rescan"
result_success = "Result Success"
title = "Scan QR Code"
camera_error = "Camera Error"
permission_error = "Permission Error"
permission_required = "Permission Required"
[msg.userfront.reset]
confirm_password = "Confirm Password"
new_password = "New Password"
submit = "Submit"
subtitle = "Subtitle"
invalid_body = "Invalid Body"
invalid_link = "Invalid Link"
invalid_title = "Invalid Title"
policy_loading = "Policy Loading"
success = "Success"
[msg.userfront.reset.error]
empty_password = "Please enter Password."
generic = "Generic"
lowercase = "Lowercase"
min_length = "Min Length"
min_types = "Min Types"
mismatch = "Mismatch"
number = "Number"
symbol = "Symbol"
uppercase = "Uppercase"
[msg.userfront.reset.policy]
lowercase = "Lowercase"
min_length = "Min Length"
min_types = "Min Types"
number = "Number"
symbol = "Symbol"
uppercase = "Uppercase"
[msg.userfront.sections]
apps_subtitle = "Apps Subtitle"
audit_subtitle = "Audit Subtitle"
[msg.userfront.settings]
disabled = "Disabled"
[msg.userfront.signup]
failed = "Failed"
privacy_full = "Privacy Full"
tos_full = "Tos Full"
[msg.userfront.signup.agreement]
title = "Agreement Title"
[msg.userfront.signup.auth]
affiliate_notice = "Affiliate Notice"
title = "Auth Title"
[msg.userfront.signup.email]
code_mismatch = "Code Mismatch"
duplicate = "Duplicate"
invalid = "Invalid"
send_failed = "Send Failed"
verified = "Verified"
verify_failed = "Verify Failed"
[msg.userfront.signup.password]
length_required = "Length Required"
lowercase_required = "Lowercase Required"
mismatch = "Mismatch"
number_required = "Number Required"
symbol_required = "Symbol Required"
title = "Password Title"
uppercase_required = "Uppercase Required"
[msg.userfront.signup.password.rule]
lowercase = "Lowercase"
min_length = "Min Length"
min_types = "Min Types"
number = "Number"
symbol = "Symbol"
uppercase = "Uppercase"
[msg.userfront.signup.phone]
code_mismatch = "Code Mismatch"
send_failed = "Send Failed"
verified = "Verified"
verify_failed = "Verify Failed"
[msg.userfront.signup.policy]
loading = "Loading"
lowercase = "Lowercase"
min_length = "Min Length"
min_types = "Min Types"
number = "Number"
summary = "Summary"
symbol = "Symbol"
uppercase = "Uppercase"
[msg.userfront.signup.profile]
affiliate_hint = "Affiliate Hint"
title = "Profile Title"
[msg.userfront.signup.success]
body = "Body"
title = "Title"
[ui]
@@ -688,6 +779,7 @@ time = "TIME"
import_csv = "Import Csv"
[ui.admin.groups.create]
description = "Adds a new organization unit such as a department or team."
title = "Title"
[ui.admin.groups.detail]
@@ -704,6 +796,7 @@ desc_label = "Description"
desc_placeholder = "Desc Placeholder"
name_label = "Group Name"
name_placeholder = "Name Placeholder"
parent_label = "Parent Unit"
submit = "Submit"
unit_level_label = "Unit Level Label"
unit_level_placeholder = "Unit Level Placeholder"
@@ -859,6 +952,18 @@ name = "NAME"
role = "ROLE"
status = "STATUS"
[ui.admin.tenants.profile]
allowed_domains = "Allowed Domains"
allowed_domains_help = "Users with these email domains will be automatically assigned to this tenant."
approve_button = "Approve Tenant"
description = "Description"
name = "Tenant Name"
slug = "Slug"
status = "Status"
subtitle = "Slug and status changes are applied immediately."
title = "Tenant Profile"
type = "Type"
[ui.admin.tenants.registry]
title = "Tenant registry"
@@ -942,12 +1047,16 @@ department = "Department"
department_placeholder = "Department Placeholder"
email = "Email"
email_placeholder = "user@example.com"
job_title = "Job Title"
job_title_placeholder = "e.g. Frontend Developer"
name = "Name"
name_placeholder = "Name Placeholder"
password = "Password"
password_placeholder = "********"
phone = "Phone number"
phone_placeholder = "010-1234-5678"
position = "Position"
position_placeholder = "e.g. Senior"
role = "Role"
tenant = "Tenant"
tenant_global = "Tenant Global"
@@ -967,7 +1076,10 @@ section = "Users"
multi_title = "Per-tenant Profile Management"
[ui.admin.users.detail.form]
name_required = "Name is required."
department = "Department"
department_placeholder = "Department Placeholder"
name = "Name"
name_placeholder = "Name Placeholder"
phone = "Phone number"
phone_placeholder = "010-1234-5678"
role = "Role"
@@ -992,6 +1104,7 @@ empty = "Empty"
fetch_error = "Fetch Error"
search_placeholder = "Search Placeholder"
subtitle = "Subtitle"
title = "User Manage"
[ui.admin.users.list.breadcrumb]
list = "List"
@@ -1005,6 +1118,7 @@ tenant = "Tenant Filter"
[ui.admin.users.list.registry]
count = "Count"
title = "User Registry"
[ui.admin.users.list.table]
actions = "ACTIONS"
@@ -1148,6 +1262,7 @@ revoke = "Revoke"
revoked_at = "Revoked: "
scope_label = "Scope:"
search_placeholder = "Search Placeholder"
status_all = "All Statuses"
status_label = "Status:"
status_revoked = "Revoked"
subject = "Subject"
@@ -1155,6 +1270,7 @@ title = "User Consent Grants"
[ui.dev.clients.consents.breadcrumb]
clients = "Clients"
current = "User Consent Grants"
home = "Home"
[ui.dev.clients.consents.filters]
@@ -1248,7 +1364,9 @@ pkce = "PKCE"
title = "Security Settings"
[ui.dev.clients.help]
docs_body = "Includes PKCE, client_secret_basic, redirect URI validation tips."
docs_title = "Docs & Examples"
subtitle = "Developer guides for Confidential/Public clients, redirect URIs, and auth methods."
title = "Need help with OIDC configuration?"
view_guides = "View guides"
@@ -1265,9 +1383,15 @@ subtitle = "Tenant admin on-call"
title = "Owner"
[ui.dev.clients.registry]
description = "OIDC 앱, 인증 방식, 리다이렉트 URI, 비밀키 재발행을 감사 로그와 함께 관리합니다."
subtitle = "Applications"
title = "RP registry"
[ui.dev.clients.scopes]
email = "Email"
openid = "Openid"
profile = "Profile"
[ui.dev.clients.table]
actions = "Actions"
application = "Application"
@@ -1277,8 +1401,8 @@ status = "Status"
type = "Type"
[ui.dev.clients.type]
private = "Server side App"
pkce = "PKCE"
private = "Server side App"
[ui.dev.dashboard]
ready_badge = "devfront ready"
@@ -1470,6 +1594,9 @@ organization = "Organization"
security = "Security"
[ui.userfront.qr]
camera_error = "Camera Error"
permission_error = "Permission Error"
permission_required = "Permission Required"
rescan = "Rescan"
result_success = "Result Success"
title = "Scan QR Code"

View File

@@ -116,6 +116,10 @@ count = "로드된 로그 {{count}}건"
[msg.admin.groups]
[msg.admin.groups.create]
description = "부서나 팀과 같은 새로운 조직 단위를 추가합니다."
title = "새 조직 단위 생성"
[msg.admin.groups.list]
create_error = "생성 실패"
create_success = "조직 단위가 생성되었습니다."
@@ -775,6 +779,7 @@ time = "TIME"
import_csv = "CSV 임포트"
[ui.admin.groups.create]
description = "부서나 팀과 같은 새로운 조직 단위를 추가합니다."
title = "새 그룹 생성"
[ui.admin.groups.detail]
@@ -791,6 +796,7 @@ desc_label = "설명"
desc_placeholder = "그룹 용도 설명"
name_label = "그룹 이름"
name_placeholder = "예: 개발팀, 인사팀"
parent_label = "상위 조직"
submit = "생성하기"
unit_level_label = "조직 레벨"
unit_level_placeholder = "예: 본부, 팀"
@@ -849,7 +855,7 @@ view_audit_logs = "감사 로그 보기"
audit_events_24h = "24시간 이벤트"
oidc_clients = "OIDC 클라이언트"
policy_gate = "정책 게이트"
total_tenants = "전체 테넌트"
total_tenants = "전체 테넌트"
[ui.admin.profile]
manageable_tenants = "관리 가능한 테넌트"
@@ -946,6 +952,18 @@ name = "NAME"
role = "ROLE"
status = "STATUS"
[ui.admin.tenants.profile]
allowed_domains = "허용된 도메인 (콤마로 구분)"
allowed_domains_help = "이 도메인을 가진 이메일로 가입한 사용자는 자동으로 이 테넌트에 배정됩니다."
approve_button = "테넌트 승인"
description = "설명"
name = "테넌트 이름"
slug = "슬러그 (Slug)"
status = "상태"
subtitle = "슬러그 및 상태 변경은 즉시 적용됩니다."
title = "테넌트 프로필"
type = "테넌트 유형"
[ui.admin.tenants.registry]
title = "Tenant registry"
@@ -1029,12 +1047,16 @@ department = "부서"
department_placeholder = "개발팀"
email = "이메일"
email_placeholder = "user@example.com"
job_title = "직무"
job_title_placeholder = "프론트엔드 개발"
name = "이름"
name_placeholder = "홍길동"
password = "비밀번호"
password_placeholder = "********"
phone = "전화번호"
phone_placeholder = "010-1234-5678"
position = "직급"
position_placeholder = "수석/책임/선임"
role = "역할"
tenant = "테넌트"
tenant_global = "시스템 전역"
@@ -1054,7 +1076,10 @@ section = "Users"
multi_title = "테넌트별 프로필 관리"
[ui.admin.users.detail.form]
name_required = "이름은 필수입니다."
department = "부서"
department_placeholder = "개발팀"
name = "이름"
name_placeholder = "홍길동"
phone = "전화번호"
phone_placeholder = "010-1234-5678"
role = "역할"
@@ -1079,6 +1104,7 @@ empty = "검색 결과가 없습니다."
fetch_error = "사용자 목록 조회에 실패했습니다."
search_placeholder = "이름 또는 이메일 검색..."
subtitle = "시스템 사용자를 조회하고 관리합니다."
title = "사용자 관리"
[ui.admin.users.list.breadcrumb]
list = "List"
@@ -1092,6 +1118,7 @@ tenant = "테넌트 필터"
[ui.admin.users.list.registry]
count = "총 {{count}}명의 사용자가 등록되어 있습니다."
title = "사용자 레지스트리"
[ui.admin.users.list.table]
actions = "ACTIONS"
@@ -1242,6 +1269,7 @@ title = "User Consent Grants"
[ui.dev.clients.consents.breadcrumb]
clients = "Clients"
current = "User Consent Grants"
home = "Home"
[ui.dev.clients.consents.filters]
@@ -1335,7 +1363,9 @@ pkce = "PKCE"
title = "보안 설정"
[ui.dev.clients.help]
docs_body = "Includes PKCE, client_secret_basic, redirect URI validation tips."
docs_title = "Docs & Examples"
subtitle = "Developer guides for Confidential/Public clients, redirect URIs, and auth methods."
title = "Need help with OIDC configuration?"
view_guides = "View guides"
@@ -1352,9 +1382,15 @@ subtitle = "Tenant admin on-call"
title = "Owner"
[ui.dev.clients.registry]
description = "OIDC 앱, 인증 방식, 리다이렉트 URI, 비밀키 재발행을 감사 로그와 함께 관리합니다."
subtitle = "연동 앱"
title = "RP registry"
[ui.dev.clients.scopes]
email = "이메일 주소 접근"
openid = "OIDC 인증 필수 스코프"
profile = "기본 프로필 정보 접근"
[ui.dev.clients.table]
actions = "액션"
application = "애플리케이션"
@@ -1402,8 +1438,8 @@ plane = "Dev Plane"
subtitle = "Manage your applications"
[ui.dev.session]
active = "만료 시간 확인 중..."
unknown = "확인 불가"
active = "세션 활성"
unknown = "알 수 없음"
expired = "세션 만료"
expiring = "만료 임박: {{minutes}}분 {{seconds}}초 남음"
remaining = "만료 예정: {{minutes}}분 {{seconds}}초 남음"

View File

@@ -116,6 +116,10 @@ count = ""
[msg.admin.groups]
[msg.admin.groups.create]
description = ""
title = ""
[msg.admin.groups.list]
create_error = ""
create_success = ""
@@ -775,6 +779,7 @@ time = ""
import_csv = ""
[ui.admin.groups.create]
description = ""
title = ""
[ui.admin.groups.detail]
@@ -791,6 +796,7 @@ desc_label = ""
desc_placeholder = ""
name_label = ""
name_placeholder = ""
parent_label = ""
submit = ""
unit_level_label = ""
unit_level_placeholder = ""
@@ -946,6 +952,18 @@ name = ""
role = ""
status = ""
[ui.admin.tenants.profile]
allowed_domains = ""
allowed_domains_help = ""
approve_button = ""
description = ""
name = ""
slug = ""
status = ""
subtitle = ""
title = ""
type = ""
[ui.admin.tenants.registry]
title = ""
@@ -1029,12 +1047,16 @@ department = ""
department_placeholder = ""
email = ""
email_placeholder = ""
job_title = ""
job_title_placeholder = ""
name = ""
name_placeholder = ""
password = ""
password_placeholder = ""
phone = ""
phone_placeholder = ""
position = ""
position_placeholder = ""
role = ""
tenant = ""
tenant_global = ""
@@ -1054,7 +1076,10 @@ section = ""
multi_title = ""
[ui.admin.users.detail.form]
name_required = ""
department = ""
department_placeholder = ""
name = ""
name_placeholder = ""
phone = ""
phone_placeholder = ""
role = ""
@@ -1079,6 +1104,7 @@ empty = ""
fetch_error = ""
search_placeholder = ""
subtitle = ""
title = ""
[ui.admin.users.list.breadcrumb]
list = ""
@@ -1092,6 +1118,7 @@ tenant = ""
[ui.admin.users.list.registry]
count = ""
title = ""
[ui.admin.users.list.table]
actions = ""
@@ -1242,6 +1269,7 @@ title = ""
[ui.dev.clients.consents.breadcrumb]
clients = ""
current = ""
home = ""
[ui.dev.clients.consents.filters]
@@ -1335,7 +1363,9 @@ pkce = ""
title = ""
[ui.dev.clients.help]
docs_body = ""
docs_title = ""
subtitle = ""
title = ""
view_guides = ""
@@ -1352,9 +1382,15 @@ subtitle = ""
title = ""
[ui.dev.clients.registry]
description = ""
subtitle = ""
title = ""
[ui.dev.clients.scopes]
email = ""
openid = ""
profile = ""
[ui.dev.clients.table]
actions = ""
application = ""
@@ -1364,8 +1400,8 @@ status = ""
type = ""
[ui.dev.clients.type]
private = ""
pkce = ""
private = ""
[ui.dev.dashboard]
ready_badge = ""

View File

@@ -1,4 +1,3 @@
import 'login_challenge_loop_guard_base.dart';
import 'login_challenge_loop_guard_stub.dart'
if (dart.library.js_interop) 'login_challenge_loop_guard_web.dart';