@open-mercato/core 0.6.8-develop.6924.1.a8d208fcdc → 0.6.8-develop.6925.1.cefa200fa4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/generated/entities/role/index.js +2 -0
  3. package/dist/generated/entities/role/index.js.map +2 -2
  4. package/dist/generated/entity-fields-registry.js +1 -0
  5. package/dist/generated/entity-fields-registry.js.map +2 -2
  6. package/dist/helpers/integration/api.js +4 -0
  7. package/dist/helpers/integration/api.js.map +2 -2
  8. package/dist/modules/audit_logs/api/audit-logs/actions/redo/route.js +5 -0
  9. package/dist/modules/audit_logs/api/audit-logs/actions/redo/route.js.map +2 -2
  10. package/dist/modules/audit_logs/api/audit-logs/actions/undo/route.js +5 -0
  11. package/dist/modules/audit_logs/api/audit-logs/actions/undo/route.js.map +2 -2
  12. package/dist/modules/audit_logs/backend/audit-logs/page.js +4 -4
  13. package/dist/modules/audit_logs/backend/audit-logs/page.js.map +2 -2
  14. package/dist/modules/audit_logs/components/AuditLogsActions.js +9 -2
  15. package/dist/modules/audit_logs/components/AuditLogsActions.js.map +2 -2
  16. package/dist/modules/auth/api/login.js +5 -2
  17. package/dist/modules/auth/api/login.js.map +2 -2
  18. package/dist/modules/auth/api/users/route.js +8 -5
  19. package/dist/modules/auth/api/users/route.js.map +2 -2
  20. package/dist/modules/auth/backend/users/[id]/edit/page.js +15 -1
  21. package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
  22. package/dist/modules/auth/backend/users/page.js +7 -1
  23. package/dist/modules/auth/backend/users/page.js.map +2 -2
  24. package/dist/modules/auth/commands/users.js +175 -76
  25. package/dist/modules/auth/commands/users.js.map +2 -2
  26. package/dist/modules/auth/data/entities.js +4 -0
  27. package/dist/modules/auth/data/entities.js.map +2 -2
  28. package/dist/modules/auth/lib/sessionIntegrity.js +1 -1
  29. package/dist/modules/auth/lib/sessionIntegrity.js.map +2 -2
  30. package/dist/modules/auth/lib/setup-app.js +1 -1
  31. package/dist/modules/auth/lib/setup-app.js.map +2 -2
  32. package/dist/modules/auth/migrations/Migration20260728134212_auth.js +14 -0
  33. package/dist/modules/auth/migrations/Migration20260728134212_auth.js.map +7 -0
  34. package/generated/entities/role/index.ts +1 -0
  35. package/generated/entity-fields-registry.ts +1 -0
  36. package/package.json +7 -7
  37. package/src/helpers/integration/api.ts +13 -0
  38. package/src/modules/audit_logs/api/audit-logs/actions/redo/route.ts +7 -0
  39. package/src/modules/audit_logs/api/audit-logs/actions/undo/route.ts +9 -0
  40. package/src/modules/audit_logs/backend/audit-logs/page.tsx +4 -4
  41. package/src/modules/audit_logs/components/AuditLogsActions.tsx +20 -4
  42. package/src/modules/auth/api/login.ts +9 -2
  43. package/src/modules/auth/api/users/route.ts +8 -4
  44. package/src/modules/auth/backend/users/[id]/edit/page.tsx +17 -1
  45. package/src/modules/auth/backend/users/page.tsx +11 -0
  46. package/src/modules/auth/commands/users.ts +251 -85
  47. package/src/modules/auth/data/entities.ts +3 -0
  48. package/src/modules/auth/i18n/de.json +6 -0
  49. package/src/modules/auth/i18n/en.json +6 -0
  50. package/src/modules/auth/i18n/es.json +6 -0
  51. package/src/modules/auth/i18n/ko.json +6 -0
  52. package/src/modules/auth/i18n/pl.json +6 -0
  53. package/src/modules/auth/lib/sessionIntegrity.ts +1 -1
  54. package/src/modules/auth/lib/setup-app.ts +1 -1
  55. package/src/modules/auth/migrations/.snapshot-open-mercato.json +16 -0
  56. package/src/modules/auth/migrations/Migration20260728134212_auth.ts +14 -0
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../src/modules/auth/backend/users/%5Bid%5D/edit/page.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { usePathname } from 'next/navigation'\nimport { E } from '#generated/entities.ids.generated'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm, type CrudField, type CrudFormGroup, type CrudFieldOption } from '@open-mercato/ui/backend/CrudForm'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { deleteCrud, updateCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { AclEditor, type AclData } from '@open-mercato/core/modules/auth/components/AclEditor'\nimport { OrganizationSelect } from '@open-mercato/core/modules/directory/components/OrganizationSelect'\nimport { TenantSelect } from '@open-mercato/core/modules/directory/components/TenantSelect'\nimport { fetchRoleOptions } from '@open-mercato/core/modules/auth/backend/users/roleOptions'\nimport { WidgetVisibilityEditor, type WidgetVisibilityEditorHandle } from '@open-mercato/core/modules/dashboards/components/WidgetVisibilityEditor'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'\nimport { formatPasswordRequirements, getPasswordPolicy } from '@open-mercato/shared/lib/auth/passwordPolicy'\nimport { UserConsentsPanel } from '@open-mercato/core/modules/auth/components/UserConsentsPanel'\nimport { RecordNotFoundState, ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'\nimport { normalizeDisplayNameInput } from '@open-mercato/core/modules/auth/lib/displayName'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('auth').child({ component: 'users-edit-page' })\n\ntype EditUserFormValues = {\n email: string\n name: string\n password: string\n tenantId: string | null\n organizationId: string | null\n roles: string[]\n updatedAt?: string | null\n} & Record<string, unknown>\n\ntype LoadedUser = {\n id: string\n email: string\n name: string | null\n organizationId: string | null\n tenantId: string | null\n tenantName: string | null\n organizationName: string | null\n roles: string[]\n roleIds: string[]\n hasPassword: boolean\n updatedAt: string | null\n}\n\ntype UserApiItem = {\n id?: string | null\n email?: string | null\n name?: string | null\n organizationId?: string | null\n tenantId?: string | null\n tenantName?: string | null\n organizationName?: string | null\n roles?: unknown\n roleIds?: unknown\n hasPassword?: boolean\n updatedAt?: string | null\n updated_at?: string | null\n}\n\ntype UserListResponse = {\n items?: UserApiItem[]\n isSuperAdmin?: boolean\n}\n\ntype RoleLookupResponse = {\n items?: Array<{ id?: string | null; name?: string | null }>\n}\n\ntype FeatureCheckResponse = {\n ok?: boolean\n}\n\ntype TenantAwareOrganizationSelectProps = {\n fieldId: string\n value: string | null\n setValue: (value: string | null) => void\n tenantId: string | null\n includeInactiveIds?: Iterable<string | null | undefined>\n}\n\nfunction TenantAwareOrganizationSelectInput({\n fieldId,\n value,\n setValue,\n tenantId,\n includeInactiveIds,\n}: TenantAwareOrganizationSelectProps) {\n const prevTenantRef = React.useRef<string | null>(tenantId)\n const hydratedRef = React.useRef(false)\n const handleChange = React.useCallback((next: string | null) => {\n setValue(next ?? null)\n }, [setValue])\n\n React.useEffect(() => {\n if (!hydratedRef.current) {\n hydratedRef.current = true\n prevTenantRef.current = tenantId\n return\n }\n if (prevTenantRef.current !== tenantId) {\n prevTenantRef.current = tenantId\n setValue(null)\n }\n }, [tenantId, setValue])\n\n return (\n <OrganizationSelect\n id={fieldId}\n value={value}\n onChange={handleChange}\n required\n includeEmptyOption\n className=\"w-full h-9 rounded border pl-2 pr-7 text-sm truncate\"\n includeInactiveIds={includeInactiveIds}\n tenantId={tenantId}\n />\n )\n}\n\nexport default function EditUserPage({ params }: { params?: { id?: string } }) {\n const id = params?.id\n const t = useT()\n const pathname = usePathname()\n const tRef = React.useRef(t)\n tRef.current = t\n const [initialUser, setInitialUser] = React.useState<LoadedUser | null>(null)\n const [selectedTenantId, setSelectedTenantId] = React.useState<string | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [isNotFound, setIsNotFound] = React.useState(false)\n const [canEditOrgs, setCanEditOrgs] = React.useState(false)\n const [aclData, setAclData] = React.useState<AclData>({ isSuperAdmin: false, features: [], organizations: null })\n const [aclUpdatedAt, setAclUpdatedAt] = React.useState<string | null>(null)\n const [customFieldValues, setCustomFieldValues] = React.useState<Record<string, unknown>>({})\n const [actorIsSuperAdmin, setActorIsSuperAdmin] = React.useState(false)\n const [actorResolved, setActorResolved] = React.useState(false)\n const [initialRoleOptions, setInitialRoleOptions] = React.useState<CrudFieldOption[]>([])\n const widgetEditorRef = React.useRef<WidgetVisibilityEditorHandle | null>(null)\n const [resendingInvite, setResendingInvite] = React.useState(false)\n\n const handleResendInvite = React.useCallback(async () => {\n if (!id) return\n setResendingInvite(true)\n try {\n const { ok, result } = await apiCall<{ ok?: boolean; warning?: string }>('/api/auth/users/resend-invite', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id }),\n })\n if (ok) {\n if (result?.warning === 'invite_email_failed') {\n flash(tRef.current('auth.users.flash.inviteEmailFailed', 'Invite token created but the email could not be sent. Please check your email provider configuration.'), 'warning')\n } else {\n flash(tRef.current('auth.users.flash.inviteSent', 'Invitation email sent'), 'success')\n }\n }\n } catch (err) {\n logger.error('Failed to resend invite', { err })\n flash(tRef.current('auth.users.form.errors.inviteResend', 'Failed to send invitation email'), 'error')\n } finally {\n setResendingInvite(false)\n }\n }, [id])\n const passwordPolicy = React.useMemo(() => getPasswordPolicy(), [])\n const passwordRequirements = React.useMemo(\n () => formatPasswordRequirements(passwordPolicy, t),\n [passwordPolicy, t],\n )\n const passwordDescription = React.useMemo(() => (\n passwordRequirements\n ? t('auth.password.requirements.help', 'Password requirements: {requirements}', { requirements: passwordRequirements })\n : undefined\n ), [passwordRequirements, t])\n\n React.useEffect(() => {\n if (!initialUser) {\n setInitialRoleOptions([])\n return\n }\n const roleIds = initialUser.roleIds\n .map((roleId) => (typeof roleId === 'string' ? roleId.trim() : ''))\n .filter((roleId) => roleId.length > 0)\n const seedOptions = roleIds.map((roleId, index) => {\n const label = typeof initialUser.roles[index] === 'string' && initialUser.roles[index].trim().length\n ? initialUser.roles[index]\n : roleId\n return { value: roleId, label }\n })\n setInitialRoleOptions(seedOptions)\n if (!roleIds.length) return\n let cancelled = false\n Promise.all(roleIds.map(async (roleId) => {\n const response = await apiCall<RoleLookupResponse>(\n `/api/auth/roles?id=${encodeURIComponent(roleId)}&page=1&pageSize=1`,\n undefined,\n { fallback: { items: [] } },\n )\n if (!response.ok || !Array.isArray(response.result?.items)) return null\n const item = response.result.items.find((entry) => entry?.id === roleId) ?? response.result.items[0]\n const name = typeof item?.name === 'string' && item.name.trim().length ? item.name.trim() : null\n return name ? { value: roleId, label: name } : null\n }))\n .then((fetched) => {\n if (cancelled) return\n const byId = new Map(seedOptions.map((option) => [option.value, option]))\n fetched.forEach((option) => {\n if (option) byId.set(option.value, option)\n })\n setInitialRoleOptions(roleIds.map((roleId) => byId.get(roleId) ?? { value: roleId, label: roleId }))\n })\n .catch(() => {})\n return () => {\n cancelled = true\n }\n }, [initialUser])\n\n React.useEffect(() => {\n if (!id) {\n setLoading(false)\n setError(tRef.current('auth.users.form.errors.noId', 'No user ID provided'))\n return\n }\n let cancelled = false\n async function load() {\n setLoading(true)\n setError(null)\n setIsNotFound(false)\n setCustomFieldValues({})\n try {\n const { ok, result } = await apiCall<UserListResponse>(\n `/api/auth/users?id=${encodeURIComponent(String(id))}&page=1&pageSize=1`,\n )\n if (!ok) throw new Error(tRef.current('auth.users.form.errors.load', 'Failed to load user data'))\n const item = Array.isArray(result?.items) ? result?.items?.[0] : undefined\n if (!cancelled) {\n setActorIsSuperAdmin(Boolean(result?.isSuperAdmin))\n setActorResolved(true)\n if (!item) {\n setIsNotFound(true)\n setCustomFieldValues({})\n setInitialUser(null)\n setSelectedTenantId(null)\n } else {\n const roleNames = Array.isArray(item.roles)\n ? item.roles\n .map((role) => (typeof role === 'string' ? role : role == null ? '' : String(role)))\n .filter((role) => role.trim().length > 0)\n : []\n const roleIds = Array.isArray(item.roleIds)\n ? (item.roleIds as string[]).filter((rid) => typeof rid === 'string' && rid.trim().length > 0)\n : []\n setInitialUser({\n id: item.id ? String(item.id) : String(id),\n email: item.email ? String(item.email) : '',\n name: item.name ? String(item.name) : null,\n organizationId: item.organizationId ? String(item.organizationId) : null,\n tenantId: item.tenantId ? String(item.tenantId) : null,\n tenantName: item.tenantName ? String(item.tenantName) : null,\n organizationName: item.organizationName ? String(item.organizationName) : null,\n roles: roleNames,\n roleIds: roleIds.length > 0 ? roleIds : roleNames,\n hasPassword: item.hasPassword !== false,\n updatedAt: typeof item.updatedAt === 'string'\n ? item.updatedAt\n : typeof item.updated_at === 'string'\n ? item.updated_at\n : null,\n })\n setSelectedTenantId(item.tenantId ? String(item.tenantId) : null)\n const custom = extractCustomFieldEntries(item as Record<string, unknown>)\n setCustomFieldValues(custom)\n }\n }\n } catch (err) {\n logger.error('Failed to load user', { err })\n if (!cancelled) setError(tRef.current('auth.users.form.errors.load', 'Failed to load user data'))\n if (!cancelled) setCustomFieldValues({})\n if (!cancelled) setActorResolved(true)\n }\n if (!cancelled) setLoading(false)\n try {\n const featureCheck = await apiCall<FeatureCheckResponse>(\n '/api/auth/feature-check',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ features: ['directory.organizations.view'] }),\n },\n { fallback: { ok: false } },\n )\n if (!cancelled) setCanEditOrgs(Boolean(featureCheck.result?.ok))\n } catch (err) {\n logger.error('Failed to check features', { err })\n }\n }\n load()\n return () => { cancelled = true }\n }, [id])\n\n const selectedOrgId = initialUser?.organizationId ? String(initialUser.organizationId) : null\n const preloadedTenants = React.useMemo(() => {\n if (!selectedTenantId) return null\n const name = initialUser?.tenantId === selectedTenantId\n ? (initialUser?.tenantName ?? selectedTenantId)\n : selectedTenantId\n return [{ id: selectedTenantId, name, isActive: true }]\n }, [initialUser, selectedTenantId])\n\n // Block role loading until we know whether the actor is a super admin. Without this guard the\n // initial (non-super-admin) branch fires before the flag resolves and the server returns roles\n // from other tenants because the real caller is a super admin without tenantId scoping.\n const loadRoleOptions = React.useCallback(async (query?: string): Promise<CrudFieldOption[]> => {\n if (!actorResolved) return []\n if (actorIsSuperAdmin) {\n if (!selectedTenantId) return []\n return fetchRoleOptions(query, { tenantId: selectedTenantId, includeSuperAdmin: true })\n }\n return fetchRoleOptions(query)\n }, [actorIsSuperAdmin, actorResolved, selectedTenantId])\n\n const userHasPassword = initialUser?.hasPassword !== false\n const fields: CrudField[] = React.useMemo(() => {\n const items: CrudField[] = [\n { id: 'email', label: t('auth.users.form.field.email', 'Email'), type: 'text', required: true },\n { id: 'name', label: t('auth.users.form.field.name', 'Display name'), type: 'text' },\n {\n id: 'password',\n label: userHasPassword\n ? t('auth.users.form.field.newPassword', 'New Password')\n : t('auth.users.form.field.setPassword', 'Set Password'),\n type: 'password' as const,\n description: [\n userHasPassword\n ? t('auth.users.form.field.passwordChangeHint', 'Leave blank to keep current password')\n : t('auth.users.form.field.passwordInviteHint', 'Optionally set a password for this user (they were invited via email)'),\n passwordDescription,\n ].filter(Boolean).join('. '),\n },\n ]\n if (actorIsSuperAdmin) {\n items.push({\n id: 'tenantId',\n label: t('auth.users.form.field.tenant', 'Tenant'),\n type: 'custom',\n required: true,\n component: ({ value, setValue }) => {\n const normalizedValue = typeof value === 'string'\n ? value\n : (typeof selectedTenantId === 'string' ? selectedTenantId : null)\n return (\n <TenantSelect\n id=\"tenantId\"\n value={normalizedValue}\n onChange={(next) => {\n const resolved = next ?? null\n setValue(resolved)\n setSelectedTenantId(resolved)\n setAclData({ isSuperAdmin: false, features: [], organizations: null })\n }}\n includeEmptyOption\n className=\"w-full h-9 rounded border pl-2 pr-7 text-sm truncate\"\n required\n tenants={preloadedTenants}\n />\n )\n },\n })\n }\n items.push({\n id: 'organizationId',\n label: t('auth.users.form.field.organization', 'Organization'),\n type: 'custom',\n required: true,\n component: ({ id, value, setValue }) => {\n const normalizedValue = typeof value === 'string' ? (value.length > 0 ? value : null) : null\n return (\n <TenantAwareOrganizationSelectInput\n fieldId={id}\n value={normalizedValue}\n setValue={(next) => setValue(next ?? null)}\n tenantId={selectedTenantId}\n includeInactiveIds={selectedOrgId ? [selectedOrgId] : undefined}\n />\n )\n },\n })\n items.push({\n id: 'roles',\n label: t('auth.users.form.field.roles', 'Roles'),\n type: 'tags',\n options: initialRoleOptions,\n loadOptions: loadRoleOptions,\n })\n return items\n }, [actorIsSuperAdmin, initialRoleOptions, loadRoleOptions, passwordDescription, preloadedTenants, selectedOrgId, selectedTenantId, t, userHasPassword])\n\n const detailFieldIds = React.useMemo(() => {\n const base: string[] = ['email', 'name', 'password', 'organizationId', 'roles']\n if (actorIsSuperAdmin) base.splice(2, 0, 'tenantId')\n return base\n }, [actorIsSuperAdmin])\n\n const groups: CrudFormGroup[] = React.useMemo(() => [\n { id: 'details', title: t('auth.users.form.group.details', 'Details'), column: 1, fields: detailFieldIds },\n { id: 'custom', title: t('auth.users.form.group.customFields', 'Custom Data'), column: 2, kind: 'customFields' },\n {\n id: 'acl',\n title: t('auth.users.form.group.access', 'Access'),\n column: 1,\n component: () => (id\n ? (\n <AclEditor\n kind=\"user\"\n targetId={String(id)}\n canEditOrganizations={canEditOrgs}\n value={aclData}\n onChange={setAclData}\n onVersionChange={setAclUpdatedAt}\n userRoles={initialUser?.roles || []}\n currentUserIsSuperAdmin={actorIsSuperAdmin}\n tenantId={selectedTenantId ?? null}\n />\n )\n : null),\n },\n {\n id: 'dashboardWidgets',\n title: t('auth.users.form.group.widgets', 'Dashboard Widgets'),\n column: 2,\n component: () => (id && initialUser\n ? (\n <WidgetVisibilityEditor\n kind=\"user\"\n targetId={String(id)}\n tenantId={selectedTenantId ?? null}\n organizationId={initialUser?.organizationId ?? null}\n ref={widgetEditorRef}\n />\n ) : null\n ),\n },\n {\n id: 'consents',\n title: t('auth.users.form.group.consents', 'Consents'),\n column: 2,\n component: () => (id ? <UserConsentsPanel userId={String(id)} /> : null),\n },\n ], [aclData, actorIsSuperAdmin, canEditOrgs, detailFieldIds, id, initialUser, selectedTenantId, t])\n\n const initialValues = React.useMemo(() => {\n if (initialUser) {\n return {\n email: initialUser.email,\n name: initialUser.name ?? '',\n password: '',\n tenantId: initialUser.tenantId,\n organizationId: initialUser.organizationId,\n roles: initialUser.roleIds,\n updatedAt: initialUser.updatedAt,\n ...customFieldValues,\n }\n }\n return {\n email: '',\n name: '',\n password: '',\n tenantId: selectedTenantId ?? null,\n organizationId: null,\n roles: [],\n ...customFieldValues,\n }\n }, [initialUser, customFieldValues, selectedTenantId])\n\n // Publish page-load record context to the AppShell-owned `backend:record:current`\n // mount so the enterprise record_locks widget resolves `auth.user` + id explicitly.\n // The resourceKind mirrors the CrudForm `versionHistory` so the held lock matches\n // the save-time conflict surface for the same user.\n useSetCurrentRecordInjectionContext(\n buildRecordInjectionContext({\n resourceKind: 'auth.user',\n resourceId: id || null,\n updatedAt: initialUser?.updatedAt ?? null,\n data: initialUser as Record<string, unknown> | null,\n path: pathname,\n }),\n )\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('auth.users.form.errors.notFound', 'User not found')}\n backHref=\"/backend/users\"\n backLabel={t('auth.users.form.actions.backToList', 'Back to users')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error && !loading) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={error} />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <CrudForm<EditUserFormValues>\n title={t('auth.users.form.title.edit', 'Edit User')}\n backHref=\"/backend/users\"\n versionHistory={{ resourceKind: 'auth.user', resourceId: id ? String(id) : '' }}\n fields={fields}\n groups={groups}\n entityId={E.auth.user}\n initialValues={initialValues}\n isLoading={loading}\n loadingMessage={t('auth.users.form.loading', 'Loading user data...')}\n submitLabel={t('auth.users.form.action.save', 'Save')}\n cancelHref=\"/backend/users\"\n extraActions={id && !userHasPassword ? (\n <Button\n type=\"button\"\n variant=\"outline\"\n disabled={resendingInvite}\n onClick={handleResendInvite}\n >\n {resendingInvite\n ? t('auth.users.form.action.resendingInvite', 'Sending...')\n : t('auth.users.form.action.resendInvite', 'Resend Invite')}\n </Button>\n ) : undefined}\n successRedirect={`/backend/users?flash=${encodeURIComponent(t('auth.users.flash.updated', 'User saved'))}&type=success`}\n onSubmit={async (values) => {\n if (!id) return\n const customFields = collectCustomFieldValues(values)\n const payload = {\n id: id ? String(id) : '',\n email: values.email,\n name: normalizeDisplayNameInput(values.name),\n password: values.password && values.password.trim() ? values.password : undefined,\n organizationId: values.organizationId ? values.organizationId : undefined,\n roles: Array.isArray(values.roles) ? values.roles : [],\n ...(Object.keys(customFields).length ? { customFields } : {}),\n }\n const userOptimisticLockHeader = buildOptimisticLockHeader(initialUser?.updatedAt)\n if (Object.keys(userOptimisticLockHeader).length > 0) {\n await withScopedApiRequestHeaders(userOptimisticLockHeader, () => updateCrud('auth/users', payload))\n } else {\n await updateCrud('auth/users', payload)\n }\n // Optimistic lock the ACL save against the loaded UserAcl version so a\n // concurrent permission edit cannot silently overwrite (#2055). CrudForm\n // surfaces the 409 as the unified conflict bar.\n const aclLockHeader = buildOptimisticLockHeader(aclUpdatedAt)\n const saveUserAcl = () => updateCrud('auth/users/acl', { userId: id, ...aclData }, {\n errorMessage: t('auth.users.form.errors.aclUpdate', 'Failed to update user access control'),\n })\n if (Object.keys(aclLockHeader).length > 0) {\n await withScopedApiRequestHeaders(aclLockHeader, saveUserAcl)\n } else {\n await saveUserAcl()\n }\n await widgetEditorRef.current?.save()\n try { window.dispatchEvent(new Event('om:refresh-sidebar')) } catch {}\n }}\n onDelete={async () => {\n const userOptimisticLockHeader = buildOptimisticLockHeader(initialUser?.updatedAt)\n const deleteUser = () => deleteCrud('auth/users', String(id), {\n errorMessage: t('auth.users.form.errors.delete', 'Failed to delete user'),\n })\n if (Object.keys(userOptimisticLockHeader).length > 0) {\n await withScopedApiRequestHeaders(userOptimisticLockHeader, deleteUser)\n } else {\n await deleteUser()\n }\n }}\n deleteRedirect={`/backend/users?flash=${encodeURIComponent(t('auth.users.flash.deleted', 'User deleted'))}&type=success`}\n />\n </PageBody>\n </Page>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { usePathname } from 'next/navigation'\nimport { E } from '#generated/entities.ids.generated'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm, type CrudField, type CrudFormGroup, type CrudFieldOption } from '@open-mercato/ui/backend/CrudForm'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { deleteCrud, updateCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { AclEditor, type AclData } from '@open-mercato/core/modules/auth/components/AclEditor'\nimport { OrganizationSelect } from '@open-mercato/core/modules/directory/components/OrganizationSelect'\nimport { TenantSelect } from '@open-mercato/core/modules/directory/components/TenantSelect'\nimport { fetchRoleOptions } from '@open-mercato/core/modules/auth/backend/users/roleOptions'\nimport { WidgetVisibilityEditor, type WidgetVisibilityEditorHandle } from '@open-mercato/core/modules/dashboards/components/WidgetVisibilityEditor'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'\nimport { formatPasswordRequirements, getPasswordPolicy } from '@open-mercato/shared/lib/auth/passwordPolicy'\nimport { UserConsentsPanel } from '@open-mercato/core/modules/auth/components/UserConsentsPanel'\nimport { RecordNotFoundState, ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'\nimport { normalizeDisplayNameInput } from '@open-mercato/core/modules/auth/lib/displayName'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('auth').child({ component: 'users-edit-page' })\n\ntype EditUserFormValues = {\n email: string\n name: string\n password: string\n tenantId: string | null\n organizationId: string | null\n roles: string[]\n updatedAt?: string | null\n} & Record<string, unknown>\n\ntype LoadedUser = {\n id: string\n email: string\n name: string | null\n organizationId: string | null\n tenantId: string | null\n tenantName: string | null\n organizationName: string | null\n roles: string[]\n roleIds: string[]\n hasPassword: boolean\n isConfirmed: boolean\n updatedAt: string | null\n}\n\ntype UserApiItem = {\n id?: string | null\n email?: string | null\n name?: string | null\n organizationId?: string | null\n tenantId?: string | null\n tenantName?: string | null\n organizationName?: string | null\n roles?: unknown\n roleIds?: unknown\n hasPassword?: boolean\n isConfirmed?: boolean\n updatedAt?: string | null\n updated_at?: string | null\n}\n\ntype UserListResponse = {\n items?: UserApiItem[]\n isSuperAdmin?: boolean\n}\n\ntype RoleLookupResponse = {\n items?: Array<{ id?: string | null; name?: string | null }>\n}\n\ntype FeatureCheckResponse = {\n ok?: boolean\n}\n\ntype TenantAwareOrganizationSelectProps = {\n fieldId: string\n value: string | null\n setValue: (value: string | null) => void\n tenantId: string | null\n includeInactiveIds?: Iterable<string | null | undefined>\n}\n\nfunction TenantAwareOrganizationSelectInput({\n fieldId,\n value,\n setValue,\n tenantId,\n includeInactiveIds,\n}: TenantAwareOrganizationSelectProps) {\n const prevTenantRef = React.useRef<string | null>(tenantId)\n const hydratedRef = React.useRef(false)\n const handleChange = React.useCallback((next: string | null) => {\n setValue(next ?? null)\n }, [setValue])\n\n React.useEffect(() => {\n if (!hydratedRef.current) {\n hydratedRef.current = true\n prevTenantRef.current = tenantId\n return\n }\n if (prevTenantRef.current !== tenantId) {\n prevTenantRef.current = tenantId\n setValue(null)\n }\n }, [tenantId, setValue])\n\n return (\n <OrganizationSelect\n id={fieldId}\n value={value}\n onChange={handleChange}\n required\n includeEmptyOption\n className=\"w-full h-9 rounded border pl-2 pr-7 text-sm truncate\"\n includeInactiveIds={includeInactiveIds}\n tenantId={tenantId}\n />\n )\n}\n\nexport default function EditUserPage({ params }: { params?: { id?: string } }) {\n const id = params?.id\n const t = useT()\n const pathname = usePathname()\n const tRef = React.useRef(t)\n tRef.current = t\n const [initialUser, setInitialUser] = React.useState<LoadedUser | null>(null)\n const [selectedTenantId, setSelectedTenantId] = React.useState<string | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [isNotFound, setIsNotFound] = React.useState(false)\n const [canEditOrgs, setCanEditOrgs] = React.useState(false)\n const [aclData, setAclData] = React.useState<AclData>({ isSuperAdmin: false, features: [], organizations: null })\n const [aclUpdatedAt, setAclUpdatedAt] = React.useState<string | null>(null)\n const [customFieldValues, setCustomFieldValues] = React.useState<Record<string, unknown>>({})\n const [actorIsSuperAdmin, setActorIsSuperAdmin] = React.useState(false)\n const [actorResolved, setActorResolved] = React.useState(false)\n const [initialRoleOptions, setInitialRoleOptions] = React.useState<CrudFieldOption[]>([])\n const widgetEditorRef = React.useRef<WidgetVisibilityEditorHandle | null>(null)\n const [resendingInvite, setResendingInvite] = React.useState(false)\n\n const handleResendInvite = React.useCallback(async () => {\n if (!id) return\n setResendingInvite(true)\n try {\n const { ok, result } = await apiCall<{ ok?: boolean; warning?: string }>('/api/auth/users/resend-invite', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id }),\n })\n if (ok) {\n if (result?.warning === 'invite_email_failed') {\n flash(tRef.current('auth.users.flash.inviteEmailFailed', 'Invite token created but the email could not be sent. Please check your email provider configuration.'), 'warning')\n } else {\n flash(tRef.current('auth.users.flash.inviteSent', 'Invitation email sent'), 'success')\n }\n }\n } catch (err) {\n logger.error('Failed to resend invite', { err })\n flash(tRef.current('auth.users.form.errors.inviteResend', 'Failed to send invitation email'), 'error')\n } finally {\n setResendingInvite(false)\n }\n }, [id])\n const passwordPolicy = React.useMemo(() => getPasswordPolicy(), [])\n const passwordRequirements = React.useMemo(\n () => formatPasswordRequirements(passwordPolicy, t),\n [passwordPolicy, t],\n )\n const passwordDescription = React.useMemo(() => (\n passwordRequirements\n ? t('auth.password.requirements.help', 'Password requirements: {requirements}', { requirements: passwordRequirements })\n : undefined\n ), [passwordRequirements, t])\n\n React.useEffect(() => {\n if (!initialUser) {\n setInitialRoleOptions([])\n return\n }\n const roleIds = initialUser.roleIds\n .map((roleId) => (typeof roleId === 'string' ? roleId.trim() : ''))\n .filter((roleId) => roleId.length > 0)\n const seedOptions = roleIds.map((roleId, index) => {\n const label = typeof initialUser.roles[index] === 'string' && initialUser.roles[index].trim().length\n ? initialUser.roles[index]\n : roleId\n return { value: roleId, label }\n })\n setInitialRoleOptions(seedOptions)\n if (!roleIds.length) return\n let cancelled = false\n Promise.all(roleIds.map(async (roleId) => {\n const response = await apiCall<RoleLookupResponse>(\n `/api/auth/roles?id=${encodeURIComponent(roleId)}&page=1&pageSize=1`,\n undefined,\n { fallback: { items: [] } },\n )\n if (!response.ok || !Array.isArray(response.result?.items)) return null\n const item = response.result.items.find((entry) => entry?.id === roleId) ?? response.result.items[0]\n const name = typeof item?.name === 'string' && item.name.trim().length ? item.name.trim() : null\n return name ? { value: roleId, label: name } : null\n }))\n .then((fetched) => {\n if (cancelled) return\n const byId = new Map(seedOptions.map((option) => [option.value, option]))\n fetched.forEach((option) => {\n if (option) byId.set(option.value, option)\n })\n setInitialRoleOptions(roleIds.map((roleId) => byId.get(roleId) ?? { value: roleId, label: roleId }))\n })\n .catch(() => {})\n return () => {\n cancelled = true\n }\n }, [initialUser])\n\n React.useEffect(() => {\n if (!id) {\n setLoading(false)\n setError(tRef.current('auth.users.form.errors.noId', 'No user ID provided'))\n return\n }\n let cancelled = false\n async function load() {\n setLoading(true)\n setError(null)\n setIsNotFound(false)\n setCustomFieldValues({})\n try {\n const { ok, result } = await apiCall<UserListResponse>(\n `/api/auth/users?id=${encodeURIComponent(String(id))}&page=1&pageSize=1`,\n )\n if (!ok) throw new Error(tRef.current('auth.users.form.errors.load', 'Failed to load user data'))\n const item = Array.isArray(result?.items) ? result?.items?.[0] : undefined\n if (!cancelled) {\n setActorIsSuperAdmin(Boolean(result?.isSuperAdmin))\n setActorResolved(true)\n if (!item) {\n setIsNotFound(true)\n setCustomFieldValues({})\n setInitialUser(null)\n setSelectedTenantId(null)\n } else {\n const roleNames = Array.isArray(item.roles)\n ? item.roles\n .map((role) => (typeof role === 'string' ? role : role == null ? '' : String(role)))\n .filter((role) => role.trim().length > 0)\n : []\n const roleIds = Array.isArray(item.roleIds)\n ? (item.roleIds as string[]).filter((rid) => typeof rid === 'string' && rid.trim().length > 0)\n : []\n setInitialUser({\n id: item.id ? String(item.id) : String(id),\n email: item.email ? String(item.email) : '',\n name: item.name ? String(item.name) : null,\n organizationId: item.organizationId ? String(item.organizationId) : null,\n tenantId: item.tenantId ? String(item.tenantId) : null,\n tenantName: item.tenantName ? String(item.tenantName) : null,\n organizationName: item.organizationName ? String(item.organizationName) : null,\n roles: roleNames,\n roleIds: roleIds.length > 0 ? roleIds : roleNames,\n hasPassword: item.hasPassword !== false,\n isConfirmed: item.isConfirmed !== false,\n updatedAt: typeof item.updatedAt === 'string'\n ? item.updatedAt\n : typeof item.updated_at === 'string'\n ? item.updated_at\n : null,\n })\n setSelectedTenantId(item.tenantId ? String(item.tenantId) : null)\n const custom = extractCustomFieldEntries(item as Record<string, unknown>)\n setCustomFieldValues(custom)\n }\n }\n } catch (err) {\n logger.error('Failed to load user', { err })\n if (!cancelled) setError(tRef.current('auth.users.form.errors.load', 'Failed to load user data'))\n if (!cancelled) setCustomFieldValues({})\n if (!cancelled) setActorResolved(true)\n }\n if (!cancelled) setLoading(false)\n try {\n const featureCheck = await apiCall<FeatureCheckResponse>(\n '/api/auth/feature-check',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ features: ['directory.organizations.view'] }),\n },\n { fallback: { ok: false } },\n )\n if (!cancelled) setCanEditOrgs(Boolean(featureCheck.result?.ok))\n } catch (err) {\n logger.error('Failed to check features', { err })\n }\n }\n load()\n return () => { cancelled = true }\n }, [id])\n\n const selectedOrgId = initialUser?.organizationId ? String(initialUser.organizationId) : null\n const preloadedTenants = React.useMemo(() => {\n if (!selectedTenantId) return null\n const name = initialUser?.tenantId === selectedTenantId\n ? (initialUser?.tenantName ?? selectedTenantId)\n : selectedTenantId\n return [{ id: selectedTenantId, name, isActive: true }]\n }, [initialUser, selectedTenantId])\n\n // Block role loading until we know whether the actor is a super admin. Without this guard the\n // initial (non-super-admin) branch fires before the flag resolves and the server returns roles\n // from other tenants because the real caller is a super admin without tenantId scoping.\n const loadRoleOptions = React.useCallback(async (query?: string): Promise<CrudFieldOption[]> => {\n if (!actorResolved) return []\n if (actorIsSuperAdmin) {\n if (!selectedTenantId) return []\n return fetchRoleOptions(query, { tenantId: selectedTenantId, includeSuperAdmin: true })\n }\n return fetchRoleOptions(query)\n }, [actorIsSuperAdmin, actorResolved, selectedTenantId])\n\n const userHasPassword = initialUser?.hasPassword !== false\n const fields: CrudField[] = React.useMemo(() => {\n const items: CrudField[] = [\n { id: 'email', label: t('auth.users.form.field.email', 'Email'), type: 'text', required: true },\n { id: 'name', label: t('auth.users.form.field.name', 'Display name'), type: 'text' },\n {\n id: 'password',\n label: userHasPassword\n ? t('auth.users.form.field.newPassword', 'New Password')\n : t('auth.users.form.field.setPassword', 'Set Password'),\n type: 'password' as const,\n description: [\n userHasPassword\n ? t('auth.users.form.field.passwordChangeHint', 'Leave blank to keep current password')\n : t('auth.users.form.field.passwordInviteHint', 'Optionally set a password for this user (they were invited via email)'),\n passwordDescription,\n ].filter(Boolean).join('. '),\n },\n ]\n if (actorIsSuperAdmin) {\n items.push({\n id: 'tenantId',\n label: t('auth.users.form.field.tenant', 'Tenant'),\n type: 'custom',\n required: true,\n component: ({ value, setValue }) => {\n const normalizedValue = typeof value === 'string'\n ? value\n : (typeof selectedTenantId === 'string' ? selectedTenantId : null)\n return (\n <TenantSelect\n id=\"tenantId\"\n value={normalizedValue}\n onChange={(next) => {\n const resolved = next ?? null\n setValue(resolved)\n setSelectedTenantId(resolved)\n setAclData({ isSuperAdmin: false, features: [], organizations: null })\n }}\n includeEmptyOption\n className=\"w-full h-9 rounded border pl-2 pr-7 text-sm truncate\"\n required\n tenants={preloadedTenants}\n />\n )\n },\n })\n }\n items.push({\n id: 'organizationId',\n label: t('auth.users.form.field.organization', 'Organization'),\n type: 'custom',\n required: true,\n component: ({ id, value, setValue }) => {\n const normalizedValue = typeof value === 'string' ? (value.length > 0 ? value : null) : null\n return (\n <TenantAwareOrganizationSelectInput\n fieldId={id}\n value={normalizedValue}\n setValue={(next) => setValue(next ?? null)}\n tenantId={selectedTenantId}\n includeInactiveIds={selectedOrgId ? [selectedOrgId] : undefined}\n />\n )\n },\n })\n items.push({\n id: 'roles',\n label: t('auth.users.form.field.roles', 'Roles'),\n type: 'tags',\n options: initialRoleOptions,\n loadOptions: loadRoleOptions,\n })\n items.push({\n id: 'isConfirmed',\n label: t('auth.users.form.field.active', 'Active'),\n type: 'checkbox',\n description: t(\n 'auth.users.form.field.activeHint',\n 'Clearing this deactivates the account: the user can no longer sign in and every active session is revoked.',\n ),\n })\n return items\n }, [actorIsSuperAdmin, initialRoleOptions, loadRoleOptions, passwordDescription, preloadedTenants, selectedOrgId, selectedTenantId, t, userHasPassword])\n\n const detailFieldIds = React.useMemo(() => {\n const base: string[] = ['email', 'name', 'password', 'organizationId', 'roles', 'isConfirmed']\n if (actorIsSuperAdmin) base.splice(2, 0, 'tenantId')\n return base\n }, [actorIsSuperAdmin])\n\n const groups: CrudFormGroup[] = React.useMemo(() => [\n { id: 'details', title: t('auth.users.form.group.details', 'Details'), column: 1, fields: detailFieldIds },\n { id: 'custom', title: t('auth.users.form.group.customFields', 'Custom Data'), column: 2, kind: 'customFields' },\n {\n id: 'acl',\n title: t('auth.users.form.group.access', 'Access'),\n column: 1,\n component: () => (id\n ? (\n <AclEditor\n kind=\"user\"\n targetId={String(id)}\n canEditOrganizations={canEditOrgs}\n value={aclData}\n onChange={setAclData}\n onVersionChange={setAclUpdatedAt}\n userRoles={initialUser?.roles || []}\n currentUserIsSuperAdmin={actorIsSuperAdmin}\n tenantId={selectedTenantId ?? null}\n />\n )\n : null),\n },\n {\n id: 'dashboardWidgets',\n title: t('auth.users.form.group.widgets', 'Dashboard Widgets'),\n column: 2,\n component: () => (id && initialUser\n ? (\n <WidgetVisibilityEditor\n kind=\"user\"\n targetId={String(id)}\n tenantId={selectedTenantId ?? null}\n organizationId={initialUser?.organizationId ?? null}\n ref={widgetEditorRef}\n />\n ) : null\n ),\n },\n {\n id: 'consents',\n title: t('auth.users.form.group.consents', 'Consents'),\n column: 2,\n component: () => (id ? <UserConsentsPanel userId={String(id)} /> : null),\n },\n ], [aclData, actorIsSuperAdmin, canEditOrgs, detailFieldIds, id, initialUser, selectedTenantId, t])\n\n const initialValues = React.useMemo(() => {\n if (initialUser) {\n return {\n email: initialUser.email,\n name: initialUser.name ?? '',\n password: '',\n tenantId: initialUser.tenantId,\n organizationId: initialUser.organizationId,\n roles: initialUser.roleIds,\n isConfirmed: initialUser.isConfirmed,\n updatedAt: initialUser.updatedAt,\n ...customFieldValues,\n }\n }\n return {\n email: '',\n name: '',\n password: '',\n tenantId: selectedTenantId ?? null,\n organizationId: null,\n roles: [],\n ...customFieldValues,\n }\n }, [initialUser, customFieldValues, selectedTenantId])\n\n // Publish page-load record context to the AppShell-owned `backend:record:current`\n // mount so the enterprise record_locks widget resolves `auth.user` + id explicitly.\n // The resourceKind mirrors the CrudForm `versionHistory` so the held lock matches\n // the save-time conflict surface for the same user.\n useSetCurrentRecordInjectionContext(\n buildRecordInjectionContext({\n resourceKind: 'auth.user',\n resourceId: id || null,\n updatedAt: initialUser?.updatedAt ?? null,\n data: initialUser as Record<string, unknown> | null,\n path: pathname,\n }),\n )\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('auth.users.form.errors.notFound', 'User not found')}\n backHref=\"/backend/users\"\n backLabel={t('auth.users.form.actions.backToList', 'Back to users')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error && !loading) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={error} />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <CrudForm<EditUserFormValues>\n title={t('auth.users.form.title.edit', 'Edit User')}\n backHref=\"/backend/users\"\n versionHistory={{ resourceKind: 'auth.user', resourceId: id ? String(id) : '' }}\n fields={fields}\n groups={groups}\n entityId={E.auth.user}\n initialValues={initialValues}\n isLoading={loading}\n loadingMessage={t('auth.users.form.loading', 'Loading user data...')}\n submitLabel={t('auth.users.form.action.save', 'Save')}\n cancelHref=\"/backend/users\"\n extraActions={id && !userHasPassword ? (\n <Button\n type=\"button\"\n variant=\"outline\"\n disabled={resendingInvite}\n onClick={handleResendInvite}\n >\n {resendingInvite\n ? t('auth.users.form.action.resendingInvite', 'Sending...')\n : t('auth.users.form.action.resendInvite', 'Resend Invite')}\n </Button>\n ) : undefined}\n successRedirect={`/backend/users?flash=${encodeURIComponent(t('auth.users.flash.updated', 'User saved'))}&type=success`}\n onSubmit={async (values) => {\n if (!id) return\n const customFields = collectCustomFieldValues(values)\n const payload = {\n id: id ? String(id) : '',\n email: values.email,\n name: normalizeDisplayNameInput(values.name),\n password: values.password && values.password.trim() ? values.password : undefined,\n organizationId: values.organizationId ? values.organizationId : undefined,\n roles: Array.isArray(values.roles) ? values.roles : [],\n // Only sent when the checkbox actually resolved to a boolean \u2014 never\n // default a missing value to `false`, which would silently deactivate.\n ...(typeof values.isConfirmed === 'boolean' ? { isConfirmed: values.isConfirmed } : {}),\n ...(Object.keys(customFields).length ? { customFields } : {}),\n }\n const userOptimisticLockHeader = buildOptimisticLockHeader(initialUser?.updatedAt)\n if (Object.keys(userOptimisticLockHeader).length > 0) {\n await withScopedApiRequestHeaders(userOptimisticLockHeader, () => updateCrud('auth/users', payload))\n } else {\n await updateCrud('auth/users', payload)\n }\n // Optimistic lock the ACL save against the loaded UserAcl version so a\n // concurrent permission edit cannot silently overwrite (#2055). CrudForm\n // surfaces the 409 as the unified conflict bar.\n const aclLockHeader = buildOptimisticLockHeader(aclUpdatedAt)\n const saveUserAcl = () => updateCrud('auth/users/acl', { userId: id, ...aclData }, {\n errorMessage: t('auth.users.form.errors.aclUpdate', 'Failed to update user access control'),\n })\n if (Object.keys(aclLockHeader).length > 0) {\n await withScopedApiRequestHeaders(aclLockHeader, saveUserAcl)\n } else {\n await saveUserAcl()\n }\n await widgetEditorRef.current?.save()\n try { window.dispatchEvent(new Event('om:refresh-sidebar')) } catch {}\n }}\n onDelete={async () => {\n const userOptimisticLockHeader = buildOptimisticLockHeader(initialUser?.updatedAt)\n const deleteUser = () => deleteCrud('auth/users', String(id), {\n errorMessage: t('auth.users.form.errors.delete', 'Failed to delete user'),\n })\n if (Object.keys(userOptimisticLockHeader).length > 0) {\n await withScopedApiRequestHeaders(userOptimisticLockHeader, deleteUser)\n } else {\n await deleteUser()\n }\n }}\n deleteRedirect={`/backend/users?flash=${encodeURIComponent(t('auth.users.flash.deleted', 'User deleted'))}&type=success`}\n />\n </PageBody>\n </Page>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["id"]
7
7
  }
@@ -7,6 +7,7 @@ import { useSearchParams } from "next/navigation";
7
7
  import { Page, PageBody } from "@open-mercato/ui/backend/Page";
8
8
  import { DataTable } from "@open-mercato/ui/backend/DataTable";
9
9
  import { Button } from "@open-mercato/ui/primitives/button";
10
+ import { Badge } from "@open-mercato/ui/primitives/badge";
10
11
  import { RowActions } from "@open-mercato/ui/backend/RowActions";
11
12
  import { apiCall, withScopedApiRequestHeaders } from "@open-mercato/ui/backend/utils/apiCall";
12
13
  import { buildOptimisticLockHeader } from "@open-mercato/ui/backend/utils/optimisticLock";
@@ -337,7 +338,12 @@ function UsersListPage() {
337
338
  { accessorKey: "email", header: "Email" },
338
339
  { accessorKey: "name", header: t("auth.users.list.columns.name", "Display name") },
339
340
  { accessorKey: "organizationName", header: "Organization" },
340
- { accessorKey: "roles", header: "Roles", cell: ({ row }) => (row.original.roles || []).join(", ") }
341
+ { accessorKey: "roles", header: "Roles", cell: ({ row }) => (row.original.roles || []).join(", ") },
342
+ {
343
+ accessorKey: "isConfirmed",
344
+ header: t("auth.users.list.columns.status", "Status"),
345
+ cell: ({ row }) => row.original.isConfirmed === false ? /* @__PURE__ */ jsx(Badge, { variant: "neutral", dot: true, children: t("auth.users.list.status.deactivated", "Deactivated") }) : /* @__PURE__ */ jsx(Badge, { variant: "success", dot: true, children: t("auth.users.list.status.active", "Active") })
346
+ }
341
347
  ];
342
348
  if (showTenantColumn) {
343
349
  base.splice(1, 0, { accessorKey: "tenantName", header: "Tenant" });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/auth/backend/users/page.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { extensionPoints } from '@open-mercato/core/modules/auth/extension-points'\nimport Link from 'next/link'\nimport { useSearchParams } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable, type DataTableExportFormat } from '@open-mercato/ui/backend/DataTable'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport type { SortingState } from '@tanstack/react-table'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { buildOrganizationTreeOptions, formatOrganizationTreeLabel, type OrganizationTreeNode, type OrganizationTreeOption } from '@open-mercato/core/modules/directory/lib/tree'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { ListEmptyState } from '@open-mercato/ui/backend/filters/ListEmptyState'\n\ntype Row = {\n id: string\n email: string\n name: string | null\n organizationId: string | null\n organizationName?: string | null\n tenantId: string | null\n tenantName?: string | null\n roles: string[]\n updatedAt?: string | null\n}\n\ntype FilterOption = { value: string; label: string }\n\nasync function fetchOrganizationFilterOptions(): Promise<FilterOption[]> {\n const search = new URLSearchParams()\n search.set('view', 'tree')\n search.set('status', 'all')\n try {\n const call = await apiCall<{ items?: OrganizationTreeNode[] }>(\n `/api/directory/organizations?${search.toString()}`,\n )\n if (!call.ok) return []\n const nodes = Array.isArray(call.result?.items) ? (call.result!.items as OrganizationTreeNode[]) : []\n const flattened: OrganizationTreeOption[] = buildOrganizationTreeOptions(nodes)\n return flattened\n .filter((opt) => typeof opt.value === 'string' && opt.value.length > 0)\n .map((opt) => {\n const baseLabel = opt.name && opt.name.length > 0 ? opt.name : opt.value\n const depth = typeof opt.depth === 'number' ? opt.depth : 0\n const label = `${formatOrganizationTreeLabel(baseLabel, depth)}${opt.isActive === false ? ' (inactive)' : ''}`\n return { value: opt.value, label }\n })\n } catch {\n return []\n }\n}\n\nasync function fetchRoleFilterOptions(query?: string): Promise<FilterOption[]> {\n const search = new URLSearchParams()\n search.set('page', '1')\n search.set('pageSize', '50')\n if (query && query.trim()) search.set('search', query.trim())\n try {\n const call = await apiCall<{ items?: unknown[] }>(`/api/auth/roles?${search.toString()}`)\n if (!call.ok) return []\n const items = Array.isArray(call.result?.items) ? call.result!.items : []\n return items\n .map((item: any): FilterOption | null => {\n const id = typeof item?.id === 'string' ? item.id : null\n const name = typeof item?.name === 'string' ? item.name : null\n if (!id || !name) return null\n return { value: id, label: name }\n })\n .filter((opt: FilterOption | null): opt is FilterOption => opt !== null)\n } catch {\n return []\n }\n}\n\nasync function fetchRoleOptionsByIds(ids: string[]): Promise<FilterOption[]> {\n const unique = Array.from(new Set(ids.filter((id) => typeof id === 'string' && id.trim() !== '')))\n if (unique.length === 0) return []\n const results = await Promise.all(unique.map(async (id) => {\n try {\n const search = new URLSearchParams()\n search.set('id', id)\n search.set('page', '1')\n search.set('pageSize', '1')\n const call = await apiCall<{ items?: unknown[] }>(`/api/auth/roles?${search.toString()}`)\n if (!call.ok) return null\n const data = call.result\n const items = Array.isArray(data?.items) ? (data?.items as unknown[]) : []\n const match = items.find((item) => {\n if (!item || typeof item !== 'object') return false\n const entry = item as Record<string, unknown>\n return typeof entry.id === 'string' && entry.id === id\n })\n const record = match && typeof match === 'object' ? (match as Record<string, unknown>) : null\n const name = typeof record?.name === 'string' ? record.name : null\n if (!name) return null\n return { value: id, label: name }\n } catch {\n return null\n }\n }))\n return results.filter((opt: FilterOption | null): opt is FilterOption => opt !== null)\n}\n\nfunction mergeOptions(existing: FilterOption[], next: FilterOption[]): FilterOption[] {\n if (!next.length) return existing\n const map = new Map<string, FilterOption>()\n for (const opt of existing) map.set(opt.value, opt)\n for (const opt of next) map.set(opt.value, opt)\n return Array.from(map.values()).sort((a, b) => a.label.localeCompare(b.label))\n}\n\nfunction arraysEqual(a: string[], b: string[]): boolean {\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i += 1) {\n if (a[i] !== b[i]) return false\n }\n return true\n}\n\nexport default function UsersListPage() {\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const searchParams = useSearchParams()\n const scopeVersion = useOrganizationScopeVersion()\n const queryClient = useQueryClient()\n const t = useT()\n const [sorting, setSorting] = React.useState<SortingState>([{ id: 'email', desc: false }])\n const [page, setPage] = React.useState(1)\n const [search, setSearch] = React.useState('')\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [organizationOptions, setOrganizationOptions] = React.useState<FilterOption[]>([])\n const [roleOptions, setRoleOptions] = React.useState<FilterOption[]>([])\n const [roleIdToLabel, setRoleIdToLabel] = React.useState<Record<string, string>>({})\n const [roleFilterDirty, setRoleFilterDirty] = React.useState(false)\n\n const roleIdsFromUrl = React.useMemo(() => {\n if (!searchParams) return [] as string[]\n const raw = searchParams.getAll('roleId')\n return raw.filter((id): id is string => typeof id === 'string' && id.trim() !== '')\n }, [searchParams])\n\n const roleIdsFromUrlKey = React.useMemo(() => roleIdsFromUrl.join('|'), [roleIdsFromUrl])\n const organizationId = typeof filterValues.organizationId === 'string' && filterValues.organizationId ? filterValues.organizationId : undefined\n\n const applyRoleOptions = React.useCallback((opts: FilterOption[]) => {\n if (!opts.length) return\n setRoleOptions((prev) => mergeOptions(prev, opts))\n setRoleIdToLabel((prev) => {\n if (!opts.length) return prev\n const next = { ...prev }\n for (const opt of opts) next[opt.value] = opt.label\n return next\n })\n }, [])\n\n React.useEffect(() => {\n let cancelled = false\n fetchOrganizationFilterOptions().then((opts) => {\n if (!cancelled) setOrganizationOptions(opts)\n })\n return () => { cancelled = true }\n }, [scopeVersion])\n\n React.useEffect(() => {\n let cancelled = false\n fetchRoleFilterOptions().then((opts) => {\n if (!cancelled) applyRoleOptions(opts)\n })\n return () => { cancelled = true }\n }, [applyRoleOptions])\n\n React.useEffect(() => {\n if (roleFilterDirty) return\n if (roleIdsFromUrl.length === 0) {\n setFilterValues((prev) => {\n if (!Array.isArray(prev.roles) || prev.roles.length === 0) return prev\n const next = { ...prev }\n delete (next as any).roles\n return next\n })\n return\n }\n const missing = roleIdsFromUrl.filter((id) => !roleIdToLabel[id])\n if (missing.length === 0) {\n setFilterValues((prev) => {\n const current = Array.isArray(prev.roles) ? prev.roles as string[] : []\n if (arraysEqual(current, roleIdsFromUrl)) return prev\n return { ...prev, roles: roleIdsFromUrl }\n })\n return\n }\n let cancelled = false\n ;(async () => {\n const fetched = await fetchRoleOptionsByIds(missing)\n if (cancelled) return\n if (fetched.length) applyRoleOptions(fetched)\n setFilterValues((prev) => {\n const current = Array.isArray(prev.roles) ? prev.roles as string[] : []\n if (arraysEqual(current, roleIdsFromUrl)) return prev\n return { ...prev, roles: roleIdsFromUrl }\n })\n })()\n return () => { cancelled = true }\n }, [roleFilterDirty, roleIdsFromUrlKey, roleIdsFromUrl, roleIdToLabel, applyRoleOptions])\n\n React.useEffect(() => {\n setRoleFilterDirty(false)\n }, [roleIdsFromUrlKey])\n\n const loadRoleOptions = React.useCallback(async (query?: string) => {\n const opts = await fetchRoleFilterOptions(query)\n if (opts.length) applyRoleOptions(opts)\n return opts\n }, [applyRoleOptions])\n\n const filters = React.useMemo<FilterDef[]>(() => [\n {\n id: 'name',\n label: t('auth.users.list.filters.name', 'Display name'),\n type: 'text',\n placeholder: t('auth.users.list.filters.namePlaceholder', 'Filter by display name'),\n },\n {\n id: 'organizationId',\n label: t('auth.users.list.filters.organization', 'Organization'),\n type: 'select',\n options: organizationOptions,\n },\n {\n id: 'roles',\n label: t('auth.users.list.filters.roles', 'Roles'),\n type: 'tags',\n placeholder: t('auth.users.list.filters.rolesPlaceholder', 'Filter by roles'),\n options: roleOptions,\n loadOptions: loadRoleOptions,\n formatValue: (val: string) => roleIdToLabel[val] ?? val,\n },\n ], [organizationOptions, roleOptions, loadRoleOptions, roleIdToLabel, t])\n\n const roleIdsFromFilter = React.useMemo(() => {\n const raw = Array.isArray(filterValues.roles) ? filterValues.roles as string[] : []\n return raw.filter((id) => typeof id === 'string' && id.length > 0)\n }, [filterValues.roles])\n\n const effectiveRoleIds = React.useMemo(() => {\n if (roleFilterDirty) return roleIdsFromFilter\n if (roleIdsFromFilter.length > 0) return roleIdsFromFilter\n return roleIdsFromUrl\n }, [roleFilterDirty, roleIdsFromFilter, roleIdsFromUrl])\n\n const normalizedRoleIds = React.useMemo(() => {\n if (!effectiveRoleIds.length) return [] as string[]\n const unique = Array.from(new Set(effectiveRoleIds))\n unique.sort((a, b) => a.localeCompare(b))\n return unique\n }, [effectiveRoleIds])\n\n const handleSearchChange = React.useCallback((value: string) => {\n setSearch(value)\n setPage(1)\n }, [])\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n const next: FilterValues = {}\n const name = typeof values.name === 'string' ? values.name.trim() : ''\n if (name) next.name = name\n const org = typeof values.organizationId === 'string' ? values.organizationId.trim() : ''\n if (org) next.organizationId = org\n const rawRoles = Array.isArray(values.roles) ? (values.roles as string[]) : []\n const sanitizedRoles = rawRoles.map((role) => role.trim()).filter((role) => role.length > 0)\n if (sanitizedRoles.length) next.roles = sanitizedRoles\n setFilterValues(next)\n setRoleFilterDirty(true)\n setPage(1)\n }, [])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({})\n setRoleFilterDirty(true)\n setPage(1)\n }, [])\n\n const exportParams = React.useMemo(() => {\n const name = typeof filterValues.name === 'string' ? filterValues.name.trim() : ''\n return {\n page,\n pageSize: 50,\n search,\n name: name.length ? name : undefined,\n organizationId,\n roleIds: normalizedRoleIds,\n }\n }, [filterValues.name, normalizedRoleIds, organizationId, page, search])\n\n const exportConfig = React.useMemo(() => ({\n view: {\n getUrl: (format: DataTableExportFormat) => {\n const params = new URLSearchParams()\n params.set('page', String(exportParams.page))\n params.set('pageSize', String(exportParams.pageSize))\n if (exportParams.search) params.set('search', exportParams.search)\n if (exportParams.name) params.set('name', exportParams.name)\n if (exportParams.organizationId) params.set('organizationId', exportParams.organizationId)\n for (const roleId of exportParams.roleIds) params.append('roleId', roleId)\n params.set('format', format)\n params.set('exportScope', 'view')\n return `/api/auth/users?${params.toString()}`\n },\n },\n full: {\n getUrl: (format: DataTableExportFormat) => {\n const params = new URLSearchParams()\n params.set('page', String(exportParams.page))\n params.set('pageSize', String(exportParams.pageSize))\n if (exportParams.search) params.set('search', exportParams.search)\n if (exportParams.name) params.set('name', exportParams.name)\n if (exportParams.organizationId) params.set('organizationId', exportParams.organizationId)\n for (const roleId of exportParams.roleIds) params.append('roleId', roleId)\n params.set('format', format)\n params.set('exportScope', 'full')\n params.set('all', 'true')\n return `/api/auth/users?${params.toString()}`\n },\n },\n }), [exportParams])\n\n const params = React.useMemo(() => {\n const p = new URLSearchParams()\n p.set('page', String(page))\n p.set('pageSize', '50')\n if (search) p.set('search', search)\n const name = typeof filterValues.name === 'string' ? filterValues.name.trim() : ''\n if (name) p.set('name', name)\n if (organizationId) p.set('organizationId', organizationId)\n if (normalizedRoleIds.length) {\n for (const id of normalizedRoleIds) p.append('roleId', id)\n }\n return p.toString()\n }, [filterValues.name, page, search, organizationId, normalizedRoleIds])\n\n const { data: usersData, isLoading } = useQuery({\n queryKey: ['users', params, scopeVersion],\n queryFn: async () => {\n const call = await apiCall<{ items: Row[]; total: number; totalPages: number; isSuperAdmin?: boolean }>(\n `/api/auth/users?${params}`,\n )\n if (!call.ok) {\n await raiseCrudError(call.response, t('auth.users.list.error.load', 'Failed to load users'))\n }\n return call.result ?? { items: [], total: 0, totalPages: 1 }\n },\n })\n\n const rows = usersData?.items || []\n const total = usersData?.total || 0\n const totalPages = usersData?.totalPages || 1\n const isSuperAdmin = !!usersData?.isSuperAdmin\n const rowsWithOrgNames: Row[] = React.useMemo(() => rows.map(row => ({\n ...row,\n organizationName: row.organizationName ?? (row.organizationId ?? undefined),\n tenantName: row.tenantName ?? (row.tenantId ?? undefined),\n })), [rows])\n const showTenantColumn = React.useMemo(\n () => isSuperAdmin && rowsWithOrgNames.some((row) => row.tenantName),\n [isSuperAdmin, rowsWithOrgNames],\n )\n const columns = React.useMemo<ColumnDef<Row>[]>(() => {\n const base: ColumnDef<Row>[] = [\n { accessorKey: 'email', header: 'Email' },\n { accessorKey: 'name', header: t('auth.users.list.columns.name', 'Display name') },\n { accessorKey: 'organizationName', header: 'Organization' },\n { accessorKey: 'roles', header: 'Roles', cell: ({ row }) => (row.original.roles || []).join(', ') },\n ]\n if (showTenantColumn) {\n base.splice(1, 0, { accessorKey: 'tenantName', header: 'Tenant' })\n }\n return base\n }, [showTenantColumn, t])\n\n const handleDelete = React.useCallback(async (row: Row) => {\n const confirmed = await confirm({\n title: t('auth.users.list.confirmDelete', 'Delete user \"{email}\"?', { email: row.email }),\n variant: 'destructive',\n })\n if (!confirmed) return\n const deleteErrorMessage = t('auth.users.list.error.delete', 'Failed to delete user')\n try {\n const call = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(row.updatedAt),\n () => apiCall(`/api/auth/users?id=${encodeURIComponent(row.id)}`, { method: 'DELETE' }),\n )\n if (!call.ok) {\n await raiseCrudError(call.response, deleteErrorMessage)\n }\n flash(t('auth.users.flash.deleted', 'User deleted'), 'success')\n await queryClient.invalidateQueries({ queryKey: ['users'] })\n } catch (error) {\n const message = error instanceof Error ? error.message : deleteErrorMessage\n flash(message, 'error')\n }\n }, [confirm, queryClient, t])\n\n return (\n <Page>\n <PageBody>\n <DataTable\n title={t('auth.users.list.title', 'Users')}\n actions={(\n <Button asChild>\n <Link href=\"/backend/users/create\">{t('common.create', 'Create')}</Link>\n </Button>\n )}\n columns={columns}\n data={rowsWithOrgNames}\n exporter={exportConfig}\n searchValue={search}\n onSearchChange={handleSearchChange}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={handleFiltersApply}\n onFiltersClear={handleFiltersClear}\n sortable\n sorting={sorting}\n onSortingChange={setSorting}\n perspective={{ tableId: extensionPoints.hosts.usersTable.tableId }}\n emptyState={(\n <ListEmptyState\n entityName={t('auth.users.list.title', 'Users')}\n createHref=\"/backend/users/create\"\n createLabel={t('common.create', 'Create')}\n />\n )}\n rowActions={(row) => (\n <RowActions items={[\n { id: 'edit', label: t('common.edit', 'Edit'), href: `/backend/users/${row.id}/edit` },\n { id: 'show-roles', label: t('auth.users.list.actions.showRoles', 'Show roles'), href: `/backend/roles?userId=${encodeURIComponent(row.id)}` },\n { id: 'delete', label: t('common.delete', 'Delete'), destructive: true, onSelect: () => { void handleDelete(row) } },\n ]} />\n )}\n pagination={{ page, pageSize: 50, total, totalPages, onPageChange: setPage }}\n isLoading={isLoading}\n />\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { extensionPoints } from '@open-mercato/core/modules/auth/extension-points'\nimport Link from 'next/link'\nimport { useSearchParams } from 'next/navigation'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable, type DataTableExportFormat } from '@open-mercato/ui/backend/DataTable'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport type { SortingState } from '@tanstack/react-table'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { apiCall, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { useQuery, useQueryClient } from '@tanstack/react-query'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { buildOrganizationTreeOptions, formatOrganizationTreeLabel, type OrganizationTreeNode, type OrganizationTreeOption } from '@open-mercato/core/modules/directory/lib/tree'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { ListEmptyState } from '@open-mercato/ui/backend/filters/ListEmptyState'\n\ntype Row = {\n id: string\n email: string\n name: string | null\n organizationId: string | null\n organizationName?: string | null\n tenantId: string | null\n tenantName?: string | null\n roles: string[]\n isConfirmed?: boolean\n updatedAt?: string | null\n}\n\ntype FilterOption = { value: string; label: string }\n\nasync function fetchOrganizationFilterOptions(): Promise<FilterOption[]> {\n const search = new URLSearchParams()\n search.set('view', 'tree')\n search.set('status', 'all')\n try {\n const call = await apiCall<{ items?: OrganizationTreeNode[] }>(\n `/api/directory/organizations?${search.toString()}`,\n )\n if (!call.ok) return []\n const nodes = Array.isArray(call.result?.items) ? (call.result!.items as OrganizationTreeNode[]) : []\n const flattened: OrganizationTreeOption[] = buildOrganizationTreeOptions(nodes)\n return flattened\n .filter((opt) => typeof opt.value === 'string' && opt.value.length > 0)\n .map((opt) => {\n const baseLabel = opt.name && opt.name.length > 0 ? opt.name : opt.value\n const depth = typeof opt.depth === 'number' ? opt.depth : 0\n const label = `${formatOrganizationTreeLabel(baseLabel, depth)}${opt.isActive === false ? ' (inactive)' : ''}`\n return { value: opt.value, label }\n })\n } catch {\n return []\n }\n}\n\nasync function fetchRoleFilterOptions(query?: string): Promise<FilterOption[]> {\n const search = new URLSearchParams()\n search.set('page', '1')\n search.set('pageSize', '50')\n if (query && query.trim()) search.set('search', query.trim())\n try {\n const call = await apiCall<{ items?: unknown[] }>(`/api/auth/roles?${search.toString()}`)\n if (!call.ok) return []\n const items = Array.isArray(call.result?.items) ? call.result!.items : []\n return items\n .map((item: any): FilterOption | null => {\n const id = typeof item?.id === 'string' ? item.id : null\n const name = typeof item?.name === 'string' ? item.name : null\n if (!id || !name) return null\n return { value: id, label: name }\n })\n .filter((opt: FilterOption | null): opt is FilterOption => opt !== null)\n } catch {\n return []\n }\n}\n\nasync function fetchRoleOptionsByIds(ids: string[]): Promise<FilterOption[]> {\n const unique = Array.from(new Set(ids.filter((id) => typeof id === 'string' && id.trim() !== '')))\n if (unique.length === 0) return []\n const results = await Promise.all(unique.map(async (id) => {\n try {\n const search = new URLSearchParams()\n search.set('id', id)\n search.set('page', '1')\n search.set('pageSize', '1')\n const call = await apiCall<{ items?: unknown[] }>(`/api/auth/roles?${search.toString()}`)\n if (!call.ok) return null\n const data = call.result\n const items = Array.isArray(data?.items) ? (data?.items as unknown[]) : []\n const match = items.find((item) => {\n if (!item || typeof item !== 'object') return false\n const entry = item as Record<string, unknown>\n return typeof entry.id === 'string' && entry.id === id\n })\n const record = match && typeof match === 'object' ? (match as Record<string, unknown>) : null\n const name = typeof record?.name === 'string' ? record.name : null\n if (!name) return null\n return { value: id, label: name }\n } catch {\n return null\n }\n }))\n return results.filter((opt: FilterOption | null): opt is FilterOption => opt !== null)\n}\n\nfunction mergeOptions(existing: FilterOption[], next: FilterOption[]): FilterOption[] {\n if (!next.length) return existing\n const map = new Map<string, FilterOption>()\n for (const opt of existing) map.set(opt.value, opt)\n for (const opt of next) map.set(opt.value, opt)\n return Array.from(map.values()).sort((a, b) => a.label.localeCompare(b.label))\n}\n\nfunction arraysEqual(a: string[], b: string[]): boolean {\n if (a.length !== b.length) return false\n for (let i = 0; i < a.length; i += 1) {\n if (a[i] !== b[i]) return false\n }\n return true\n}\n\nexport default function UsersListPage() {\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const searchParams = useSearchParams()\n const scopeVersion = useOrganizationScopeVersion()\n const queryClient = useQueryClient()\n const t = useT()\n const [sorting, setSorting] = React.useState<SortingState>([{ id: 'email', desc: false }])\n const [page, setPage] = React.useState(1)\n const [search, setSearch] = React.useState('')\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [organizationOptions, setOrganizationOptions] = React.useState<FilterOption[]>([])\n const [roleOptions, setRoleOptions] = React.useState<FilterOption[]>([])\n const [roleIdToLabel, setRoleIdToLabel] = React.useState<Record<string, string>>({})\n const [roleFilterDirty, setRoleFilterDirty] = React.useState(false)\n\n const roleIdsFromUrl = React.useMemo(() => {\n if (!searchParams) return [] as string[]\n const raw = searchParams.getAll('roleId')\n return raw.filter((id): id is string => typeof id === 'string' && id.trim() !== '')\n }, [searchParams])\n\n const roleIdsFromUrlKey = React.useMemo(() => roleIdsFromUrl.join('|'), [roleIdsFromUrl])\n const organizationId = typeof filterValues.organizationId === 'string' && filterValues.organizationId ? filterValues.organizationId : undefined\n\n const applyRoleOptions = React.useCallback((opts: FilterOption[]) => {\n if (!opts.length) return\n setRoleOptions((prev) => mergeOptions(prev, opts))\n setRoleIdToLabel((prev) => {\n if (!opts.length) return prev\n const next = { ...prev }\n for (const opt of opts) next[opt.value] = opt.label\n return next\n })\n }, [])\n\n React.useEffect(() => {\n let cancelled = false\n fetchOrganizationFilterOptions().then((opts) => {\n if (!cancelled) setOrganizationOptions(opts)\n })\n return () => { cancelled = true }\n }, [scopeVersion])\n\n React.useEffect(() => {\n let cancelled = false\n fetchRoleFilterOptions().then((opts) => {\n if (!cancelled) applyRoleOptions(opts)\n })\n return () => { cancelled = true }\n }, [applyRoleOptions])\n\n React.useEffect(() => {\n if (roleFilterDirty) return\n if (roleIdsFromUrl.length === 0) {\n setFilterValues((prev) => {\n if (!Array.isArray(prev.roles) || prev.roles.length === 0) return prev\n const next = { ...prev }\n delete (next as any).roles\n return next\n })\n return\n }\n const missing = roleIdsFromUrl.filter((id) => !roleIdToLabel[id])\n if (missing.length === 0) {\n setFilterValues((prev) => {\n const current = Array.isArray(prev.roles) ? prev.roles as string[] : []\n if (arraysEqual(current, roleIdsFromUrl)) return prev\n return { ...prev, roles: roleIdsFromUrl }\n })\n return\n }\n let cancelled = false\n ;(async () => {\n const fetched = await fetchRoleOptionsByIds(missing)\n if (cancelled) return\n if (fetched.length) applyRoleOptions(fetched)\n setFilterValues((prev) => {\n const current = Array.isArray(prev.roles) ? prev.roles as string[] : []\n if (arraysEqual(current, roleIdsFromUrl)) return prev\n return { ...prev, roles: roleIdsFromUrl }\n })\n })()\n return () => { cancelled = true }\n }, [roleFilterDirty, roleIdsFromUrlKey, roleIdsFromUrl, roleIdToLabel, applyRoleOptions])\n\n React.useEffect(() => {\n setRoleFilterDirty(false)\n }, [roleIdsFromUrlKey])\n\n const loadRoleOptions = React.useCallback(async (query?: string) => {\n const opts = await fetchRoleFilterOptions(query)\n if (opts.length) applyRoleOptions(opts)\n return opts\n }, [applyRoleOptions])\n\n const filters = React.useMemo<FilterDef[]>(() => [\n {\n id: 'name',\n label: t('auth.users.list.filters.name', 'Display name'),\n type: 'text',\n placeholder: t('auth.users.list.filters.namePlaceholder', 'Filter by display name'),\n },\n {\n id: 'organizationId',\n label: t('auth.users.list.filters.organization', 'Organization'),\n type: 'select',\n options: organizationOptions,\n },\n {\n id: 'roles',\n label: t('auth.users.list.filters.roles', 'Roles'),\n type: 'tags',\n placeholder: t('auth.users.list.filters.rolesPlaceholder', 'Filter by roles'),\n options: roleOptions,\n loadOptions: loadRoleOptions,\n formatValue: (val: string) => roleIdToLabel[val] ?? val,\n },\n ], [organizationOptions, roleOptions, loadRoleOptions, roleIdToLabel, t])\n\n const roleIdsFromFilter = React.useMemo(() => {\n const raw = Array.isArray(filterValues.roles) ? filterValues.roles as string[] : []\n return raw.filter((id) => typeof id === 'string' && id.length > 0)\n }, [filterValues.roles])\n\n const effectiveRoleIds = React.useMemo(() => {\n if (roleFilterDirty) return roleIdsFromFilter\n if (roleIdsFromFilter.length > 0) return roleIdsFromFilter\n return roleIdsFromUrl\n }, [roleFilterDirty, roleIdsFromFilter, roleIdsFromUrl])\n\n const normalizedRoleIds = React.useMemo(() => {\n if (!effectiveRoleIds.length) return [] as string[]\n const unique = Array.from(new Set(effectiveRoleIds))\n unique.sort((a, b) => a.localeCompare(b))\n return unique\n }, [effectiveRoleIds])\n\n const handleSearchChange = React.useCallback((value: string) => {\n setSearch(value)\n setPage(1)\n }, [])\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n const next: FilterValues = {}\n const name = typeof values.name === 'string' ? values.name.trim() : ''\n if (name) next.name = name\n const org = typeof values.organizationId === 'string' ? values.organizationId.trim() : ''\n if (org) next.organizationId = org\n const rawRoles = Array.isArray(values.roles) ? (values.roles as string[]) : []\n const sanitizedRoles = rawRoles.map((role) => role.trim()).filter((role) => role.length > 0)\n if (sanitizedRoles.length) next.roles = sanitizedRoles\n setFilterValues(next)\n setRoleFilterDirty(true)\n setPage(1)\n }, [])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({})\n setRoleFilterDirty(true)\n setPage(1)\n }, [])\n\n const exportParams = React.useMemo(() => {\n const name = typeof filterValues.name === 'string' ? filterValues.name.trim() : ''\n return {\n page,\n pageSize: 50,\n search,\n name: name.length ? name : undefined,\n organizationId,\n roleIds: normalizedRoleIds,\n }\n }, [filterValues.name, normalizedRoleIds, organizationId, page, search])\n\n const exportConfig = React.useMemo(() => ({\n view: {\n getUrl: (format: DataTableExportFormat) => {\n const params = new URLSearchParams()\n params.set('page', String(exportParams.page))\n params.set('pageSize', String(exportParams.pageSize))\n if (exportParams.search) params.set('search', exportParams.search)\n if (exportParams.name) params.set('name', exportParams.name)\n if (exportParams.organizationId) params.set('organizationId', exportParams.organizationId)\n for (const roleId of exportParams.roleIds) params.append('roleId', roleId)\n params.set('format', format)\n params.set('exportScope', 'view')\n return `/api/auth/users?${params.toString()}`\n },\n },\n full: {\n getUrl: (format: DataTableExportFormat) => {\n const params = new URLSearchParams()\n params.set('page', String(exportParams.page))\n params.set('pageSize', String(exportParams.pageSize))\n if (exportParams.search) params.set('search', exportParams.search)\n if (exportParams.name) params.set('name', exportParams.name)\n if (exportParams.organizationId) params.set('organizationId', exportParams.organizationId)\n for (const roleId of exportParams.roleIds) params.append('roleId', roleId)\n params.set('format', format)\n params.set('exportScope', 'full')\n params.set('all', 'true')\n return `/api/auth/users?${params.toString()}`\n },\n },\n }), [exportParams])\n\n const params = React.useMemo(() => {\n const p = new URLSearchParams()\n p.set('page', String(page))\n p.set('pageSize', '50')\n if (search) p.set('search', search)\n const name = typeof filterValues.name === 'string' ? filterValues.name.trim() : ''\n if (name) p.set('name', name)\n if (organizationId) p.set('organizationId', organizationId)\n if (normalizedRoleIds.length) {\n for (const id of normalizedRoleIds) p.append('roleId', id)\n }\n return p.toString()\n }, [filterValues.name, page, search, organizationId, normalizedRoleIds])\n\n const { data: usersData, isLoading } = useQuery({\n queryKey: ['users', params, scopeVersion],\n queryFn: async () => {\n const call = await apiCall<{ items: Row[]; total: number; totalPages: number; isSuperAdmin?: boolean }>(\n `/api/auth/users?${params}`,\n )\n if (!call.ok) {\n await raiseCrudError(call.response, t('auth.users.list.error.load', 'Failed to load users'))\n }\n return call.result ?? { items: [], total: 0, totalPages: 1 }\n },\n })\n\n const rows = usersData?.items || []\n const total = usersData?.total || 0\n const totalPages = usersData?.totalPages || 1\n const isSuperAdmin = !!usersData?.isSuperAdmin\n const rowsWithOrgNames: Row[] = React.useMemo(() => rows.map(row => ({\n ...row,\n organizationName: row.organizationName ?? (row.organizationId ?? undefined),\n tenantName: row.tenantName ?? (row.tenantId ?? undefined),\n })), [rows])\n const showTenantColumn = React.useMemo(\n () => isSuperAdmin && rowsWithOrgNames.some((row) => row.tenantName),\n [isSuperAdmin, rowsWithOrgNames],\n )\n const columns = React.useMemo<ColumnDef<Row>[]>(() => {\n const base: ColumnDef<Row>[] = [\n { accessorKey: 'email', header: 'Email' },\n { accessorKey: 'name', header: t('auth.users.list.columns.name', 'Display name') },\n { accessorKey: 'organizationName', header: 'Organization' },\n { accessorKey: 'roles', header: 'Roles', cell: ({ row }) => (row.original.roles || []).join(', ') },\n {\n accessorKey: 'isConfirmed',\n header: t('auth.users.list.columns.status', 'Status'),\n cell: ({ row }) => (\n row.original.isConfirmed === false\n ? <Badge variant=\"neutral\" dot>{t('auth.users.list.status.deactivated', 'Deactivated')}</Badge>\n : <Badge variant=\"success\" dot>{t('auth.users.list.status.active', 'Active')}</Badge>\n ),\n },\n ]\n if (showTenantColumn) {\n base.splice(1, 0, { accessorKey: 'tenantName', header: 'Tenant' })\n }\n return base\n }, [showTenantColumn, t])\n\n const handleDelete = React.useCallback(async (row: Row) => {\n const confirmed = await confirm({\n title: t('auth.users.list.confirmDelete', 'Delete user \"{email}\"?', { email: row.email }),\n variant: 'destructive',\n })\n if (!confirmed) return\n const deleteErrorMessage = t('auth.users.list.error.delete', 'Failed to delete user')\n try {\n const call = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(row.updatedAt),\n () => apiCall(`/api/auth/users?id=${encodeURIComponent(row.id)}`, { method: 'DELETE' }),\n )\n if (!call.ok) {\n await raiseCrudError(call.response, deleteErrorMessage)\n }\n flash(t('auth.users.flash.deleted', 'User deleted'), 'success')\n await queryClient.invalidateQueries({ queryKey: ['users'] })\n } catch (error) {\n const message = error instanceof Error ? error.message : deleteErrorMessage\n flash(message, 'error')\n }\n }, [confirm, queryClient, t])\n\n return (\n <Page>\n <PageBody>\n <DataTable\n title={t('auth.users.list.title', 'Users')}\n actions={(\n <Button asChild>\n <Link href=\"/backend/users/create\">{t('common.create', 'Create')}</Link>\n </Button>\n )}\n columns={columns}\n data={rowsWithOrgNames}\n exporter={exportConfig}\n searchValue={search}\n onSearchChange={handleSearchChange}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={handleFiltersApply}\n onFiltersClear={handleFiltersClear}\n sortable\n sorting={sorting}\n onSortingChange={setSorting}\n perspective={{ tableId: extensionPoints.hosts.usersTable.tableId }}\n emptyState={(\n <ListEmptyState\n entityName={t('auth.users.list.title', 'Users')}\n createHref=\"/backend/users/create\"\n createLabel={t('common.create', 'Create')}\n />\n )}\n rowActions={(row) => (\n <RowActions items={[\n { id: 'edit', label: t('common.edit', 'Edit'), href: `/backend/users/${row.id}/edit` },\n { id: 'show-roles', label: t('auth.users.list.actions.showRoles', 'Show roles'), href: `/backend/roles?userId=${encodeURIComponent(row.id)}` },\n { id: 'delete', label: t('common.delete', 'Delete'), destructive: true, onSelect: () => { void handleDelete(row) } },\n ]} />\n )}\n pagination={{ page, pageSize: 50, total, totalPages, onPageChange: setPage }}\n isLoading={isLoading}\n />\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["params"]
7
7
  }