ultisuite-client/lib/admin-settings/map-api-org-settings.ts
R3D347HR4Y 5304790ed5
Some checks are pending
E2E / Playwright e2e (push) Waiting to run
feat(auth): enhance session management and identity provider settings
- Added SessionGuard component to manage session expiration and online status.
- Updated AuthProvider to streamline session fetching and handling.
- Introduced IdentityProvidersSection for managing OAuth, SAML, and LDAP identity providers.
- Implemented identity provider guides for easier configuration.
- Enhanced mail settings with infinite scroll option for improved user experience.
- Updated global styles and layout components for better consistency across the application.
2026-06-09 09:36:46 +02:00

231 lines
7.7 KiB
TypeScript

import type { ApiOrgPolicy, ApiOrgSettingsResponse } from "@/lib/api/admin-org-types"
import type { OrgPolicySectionKey } from "@/lib/api/admin-org-types"
import type { IntegrationEntry, OrgSettingsState, FilePolicySettings, IdentityProvidersPolicy, IdentityProvider } from "@/lib/admin-settings/org-settings-types"
const INTEGRATION_HREFS: Record<string, string> = {
authentik: "/admin/settings/authentication",
nextcloud: "/admin/settings/nextcloud",
onlyoffice: "/admin/settings/onlyoffice",
smtp: "/admin/settings/mailing",
}
function mergeIntegrations(
fromApi: IntegrationEntry[] | undefined
): IntegrationEntry[] {
if (!fromApi?.length) return []
return fromApi.map((item) => ({
...item,
href: INTEGRATION_HREFS[item.id] ?? item.href,
}))
}
const DEFAULT_IDENTITY_PROVIDERS: IdentityProvidersPolicy = {
allow_self_enrollment: true,
default_login_source: "",
providers: [],
}
function mergeIdentityProviders(
fromApi: Partial<IdentityProvidersPolicy> | undefined
): IdentityProvidersPolicy {
return {
...DEFAULT_IDENTITY_PROVIDERS,
...fromApi,
providers: (fromApi?.providers ?? []).map((provider) => ({
...provider,
allowed_email_domains: provider.allowed_email_domains ?? [],
allowed_identities: provider.allowed_identities ?? [],
allowed_organizations: provider.allowed_organizations ?? [],
default_groups: provider.default_groups ?? [],
sync_status: provider.sync_status ?? "pending",
oauth: provider.oauth
? { ...provider.oauth, client_secret: provider.oauth.client_secret ?? "" }
: undefined,
ldap: provider.ldap
? { ...provider.ldap, bind_password: provider.ldap.bind_password ?? "" }
: undefined,
saml: provider.saml
? { ...provider.saml, signing_cert: provider.saml.signing_cert ?? "" }
: undefined,
})),
}
}
function mapProviderToApi(provider: IdentityProvider) {
return {
id: provider.id,
name: provider.name,
slug: provider.slug,
type: provider.type,
enabled: provider.enabled,
authentik_pk: provider.authentik_pk,
sync_status: provider.sync_status,
sync_error: provider.sync_error,
last_synced_at: provider.last_synced_at,
allowed_email_domains: provider.allowed_email_domains,
allowed_identities: provider.allowed_identities,
allowed_organizations: provider.allowed_organizations,
default_groups: provider.default_groups,
oauth: provider.oauth,
saml: provider.saml,
ldap: provider.ldap,
}
}
const DEFAULT_FILE_POLICIES: FilePolicySettings = {
max_upload_mib: 512,
allowed_extensions: "",
block_executable: true,
external_sharing: "authenticated",
default_link_expiry_days: 30,
virus_scan_enabled: false,
virustotal_api_key: "",
retention_trash_days: 30,
}
function mergeFilePolicies(fromApi: Partial<FilePolicySettings> | undefined): FilePolicySettings {
return {
...DEFAULT_FILE_POLICIES,
...fromApi,
virustotal_api_key: fromApi?.virustotal_api_key ?? "",
}
}
export function apiOrgPolicyToStore(policy: ApiOrgPolicy): Partial<OrgSettingsState> {
return {
authentik: {
enabled: policy.authentik.enabled,
api_url: policy.authentik.api_url,
slug: policy.authentik.slug,
client_id: policy.authentik.client_id,
enforce_sso: policy.authentik.enforce_sso,
allow_password_fallback: policy.authentik.allow_password_fallback,
default_groups: policy.authentik.default_groups,
},
identityProviders: mergeIdentityProviders(policy.identity_providers),
twoFactor: {
required_for_all: policy.two_factor.required_for_all,
required_for_admins: policy.two_factor.required_for_admins,
allowed_methods: policy.two_factor.allowed_methods,
grace_period_days: policy.two_factor.grace_period_days,
remember_device_days: policy.two_factor.remember_device_days,
},
storageQuotas: { ...policy.storage_quotas },
usageQuotas: { ...policy.usage_quotas },
filePolicies: mergeFilePolicies(policy.file_policies),
llm: {
...policy.llm,
providers: policy.llm.providers ?? [],
},
search: {
...policy.search,
web_search: policy.search.web_search ?? {
default_provider_id: "brave-default",
providers: [],
},
},
administrators: policy.administrators ?? [],
nextcloud: { ...policy.nextcloud },
mailing: { ...policy.mailing },
onlyoffice: { ...policy.onlyoffice },
plugins: policy.plugins ?? [],
integrations: mergeIntegrations(policy.integrations as IntegrationEntry[]),
}
}
export function storeToApiOrgPolicy(state: OrgSettingsState): ApiOrgPolicy {
return {
authentik: {
enabled: state.authentik.enabled,
api_url: state.authentik.api_url,
slug: state.authentik.slug,
client_id: state.authentik.client_id,
enforce_sso: state.authentik.enforce_sso,
allow_password_fallback: state.authentik.allow_password_fallback,
default_groups: state.authentik.default_groups,
},
identity_providers: {
allow_self_enrollment: state.identityProviders.allow_self_enrollment,
default_login_source: state.identityProviders.default_login_source,
providers: state.identityProviders.providers.map(mapProviderToApi),
},
two_factor: {
required_for_all: state.twoFactor.required_for_all,
required_for_admins: state.twoFactor.required_for_admins,
allowed_methods: state.twoFactor.allowed_methods,
grace_period_days: state.twoFactor.grace_period_days,
remember_device_days: state.twoFactor.remember_device_days,
},
storage_quotas: { ...state.storageQuotas },
usage_quotas: { ...state.usageQuotas },
file_policies: { ...state.filePolicies },
llm: {
default_provider_id: state.llm.default_provider_id,
providers: state.llm.providers,
contact_discovery_model: state.llm.contact_discovery_model,
contact_discovery_provider_id: state.llm.contact_discovery_provider_id,
enforce_org_providers: state.llm.enforce_org_providers,
allow_user_override: state.llm.allow_user_override,
},
search: {
suite_engine: state.search.suite_engine,
meilisearch_url: state.search.meilisearch_url,
meilisearch_api_key: state.search.meilisearch_api_key,
typesense_url: state.search.typesense_url,
typesense_api_key: state.search.typesense_api_key,
web_search: state.search.web_search,
enforce_org_search: state.search.enforce_org_search,
},
administrators: state.administrators,
nextcloud: { ...state.nextcloud },
mailing: { ...state.mailing },
onlyoffice: { ...state.onlyoffice },
plugins: state.plugins.map(({ id, name, description, enabled, version }) => ({
id,
name,
description,
enabled,
version,
})),
integrations: state.integrations.map(({ id, name, description, enabled, configured }) => ({
id,
name,
description,
enabled,
configured,
})),
}
}
export function pickApiOrgPolicySections(
state: OrgSettingsState,
sections: OrgPolicySectionKey[]
): Partial<ApiOrgPolicy> {
const full = storeToApiOrgPolicy(state)
const patch: Partial<ApiOrgPolicy> = {}
for (const key of sections) {
patch[key] = full[key] as never
}
return patch
}
export type OrgSettingsMeta = {
effective: ApiOrgSettingsResponse["effective"]
secrets: ApiOrgSettingsResponse["secrets"]
envVars: ApiOrgSettingsResponse["env_vars"]
deployLocked: ApiOrgSettingsResponse["deploy_locked"]
updatedAt: string
updatedBy: string
}
export function apiOrgSettingsMeta(data: ApiOrgSettingsResponse): OrgSettingsMeta {
return {
effective: data.effective,
secrets: data.secrets,
envVars: data.env_vars ?? [],
deployLocked: data.deploy_locked ?? {},
updatedAt: data.updated_at,
updatedBy: data.updated_by,
}
}