ultisuite-client/lib/admin-settings/org-settings-store.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

314 lines
9.1 KiB
TypeScript

"use client"
import { create } from "zustand"
import type { OrgSettingsMeta } from "@/lib/admin-settings/map-api-org-settings"
import type {
Administrator,
AuthentikSettings,
FilePolicySettings,
IntegrationEntry,
MailingSettings,
NextcloudSettings,
OnlyOfficeSettings,
OrgLLMSettings,
OrgSearchSettings,
OrgStorageQuotas,
PluginEntry,
TwoFactorPolicy,
UsageQuotaDefaults,
IdentityProvidersPolicy,
} from "@/lib/admin-settings/org-settings-types"
const DEFAULT_AUTHENTIK: AuthentikSettings = {
enabled: true,
api_url: "",
slug: "ulti-suite",
client_id: "",
enforce_sso: true,
allow_password_fallback: false,
default_groups: "ulti-users",
}
const DEFAULT_IDENTITY_PROVIDERS: IdentityProvidersPolicy = {
allow_self_enrollment: true,
default_login_source: "",
providers: [],
}
const DEFAULT_TWO_FACTOR: TwoFactorPolicy = {
required_for_all: false,
required_for_admins: true,
allowed_methods: ["totp", "webauthn"],
grace_period_days: 7,
remember_device_days: 30,
}
const DEFAULT_STORAGE_QUOTAS: OrgStorageQuotas = {
default_mail_gib: 5,
default_drive_gib: 5,
default_photos_gib: 5,
warn_threshold_pct: 90,
}
const DEFAULT_USAGE_QUOTAS: UsageQuotaDefaults = {
llm_requests_per_day: 100,
llm_tokens_per_month: 500_000,
search_requests_per_day: 50,
max_api_tokens_per_user: 10,
max_webhooks_per_user: 20,
}
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,
}
const DEFAULT_LLM: OrgLLMSettings = {
default_provider_id: "",
providers: [],
enforce_org_providers: false,
allow_user_override: true,
}
const DEFAULT_SEARCH: OrgSearchSettings = {
suite_engine: "postgres",
meilisearch_url: "",
meilisearch_api_key: "",
typesense_url: "",
typesense_api_key: "",
web_search: { default_provider_id: "brave-default", providers: [] },
enforce_org_search: false,
}
const DEFAULT_NEXTCLOUD: NextcloudSettings = {
enabled: false,
base_url: "",
admin_user: "",
admin_password: "",
drive_enabled: true,
calendar_enabled: true,
contacts_enabled: true,
talk_enabled: false,
}
const DEFAULT_MAILING: MailingSettings = {
enabled: false,
smtp_host: "",
smtp_port: 587,
smtp_user: "",
smtp_password: "",
from_email: "noreply@example.com",
from_name: "Ulti Suite",
tls_mode: "starttls",
}
const DEFAULT_ONLYOFFICE: OnlyOfficeSettings = {
enabled: false,
document_server_url: "",
jwt_secret: "",
jwt_header: "Authorization",
}
const DEFAULT_PLUGINS: PluginEntry[] = [
{
id: "mail-automation",
name: "Automatisations mail",
description: "Règles, webhooks et tri IA sur la réception.",
enabled: true,
version: "1.0.0",
},
{
id: "contact-discovery",
name: "Découverte contacts",
description: "Enrichissement IA et signatures détectées.",
enabled: true,
version: "1.0.0",
},
{
id: "public-share",
name: "Partage public Drive",
description: "Liens publics et partages externes.",
enabled: true,
version: "1.0.0",
},
{
id: "office-editor",
name: "Édition OnlyOffice",
description: "Édition collaborative de documents.",
enabled: false,
version: "1.0.0",
},
]
const DEFAULT_INTEGRATIONS: IntegrationEntry[] = [
{
id: "authentik",
name: "Authentik",
description: "SSO, groupes et provisionnement des comptes.",
enabled: true,
configured: false,
href: "/admin/settings/authentication",
},
{
id: "nextcloud",
name: "Nextcloud",
description: "Drive, agenda, contacts et Talk.",
enabled: false,
configured: false,
href: "/admin/settings/nextcloud",
},
{
id: "onlyoffice",
name: "OnlyOffice",
description: "Édition de documents dans le navigateur.",
enabled: false,
configured: false,
href: "/admin/settings/onlyoffice",
},
{
id: "smtp",
name: "Mailing unifié",
description: "SMTP pour notifications suite (partages, mentions).",
enabled: false,
configured: false,
href: "/admin/settings/mailing",
},
]
type OrgSettingsActions = {
setAuthentik: (patch: Partial<AuthentikSettings>) => void
setIdentityProviders: (patch: Partial<IdentityProvidersPolicy>) => void
setTwoFactor: (patch: Partial<TwoFactorPolicy>) => void
setStorageQuotas: (patch: Partial<OrgStorageQuotas>) => void
setUsageQuotas: (patch: Partial<UsageQuotaDefaults>) => void
setFilePolicies: (patch: Partial<FilePolicySettings>) => void
setLlm: (patch: Partial<OrgLLMSettings>) => void
setSearch: (patch: Partial<OrgSearchSettings>) => void
setNextcloud: (patch: Partial<NextcloudSettings>) => void
setMailing: (patch: Partial<MailingSettings>) => void
setOnlyoffice: (patch: Partial<OnlyOfficeSettings>) => void
setAdministrators: (admins: Administrator[]) => void
addAdministrator: (admin: Administrator) => void
removeAdministrator: (id: string) => void
updateAdministrator: (id: string, patch: Partial<Administrator>) => void
setPlugins: (plugins: PluginEntry[]) => void
togglePlugin: (id: string, enabled: boolean) => void
setIntegrations: (integrations: IntegrationEntry[]) => void
toggleIntegration: (id: string, enabled: boolean) => void
hydrateFromApi: (patch: Partial<{
authentik: AuthentikSettings
identityProviders: IdentityProvidersPolicy
twoFactor: TwoFactorPolicy
storageQuotas: OrgStorageQuotas
usageQuotas: UsageQuotaDefaults
filePolicies: FilePolicySettings
llm: OrgLLMSettings
search: OrgSearchSettings
administrators: Administrator[]
nextcloud: NextcloudSettings
mailing: MailingSettings
onlyoffice: OnlyOfficeSettings
plugins: PluginEntry[]
integrations: IntegrationEntry[]
}>, meta?: OrgSettingsMeta) => void
}
export const useOrgSettingsStore = create<
{
authentik: AuthentikSettings
identityProviders: IdentityProvidersPolicy
twoFactor: TwoFactorPolicy
storageQuotas: OrgStorageQuotas
usageQuotas: UsageQuotaDefaults
filePolicies: FilePolicySettings
llm: OrgLLMSettings
search: OrgSearchSettings
administrators: Administrator[]
nextcloud: NextcloudSettings
mailing: MailingSettings
onlyoffice: OnlyOfficeSettings
plugins: PluginEntry[]
integrations: IntegrationEntry[]
meta: OrgSettingsMeta | null
apiSynced: boolean
} & OrgSettingsActions
>()((set) => ({
authentik: DEFAULT_AUTHENTIK,
identityProviders: DEFAULT_IDENTITY_PROVIDERS,
twoFactor: DEFAULT_TWO_FACTOR,
storageQuotas: DEFAULT_STORAGE_QUOTAS,
usageQuotas: DEFAULT_USAGE_QUOTAS,
filePolicies: DEFAULT_FILE_POLICIES,
llm: DEFAULT_LLM,
search: DEFAULT_SEARCH,
administrators: [],
nextcloud: DEFAULT_NEXTCLOUD,
mailing: DEFAULT_MAILING,
onlyoffice: DEFAULT_ONLYOFFICE,
plugins: DEFAULT_PLUGINS,
integrations: DEFAULT_INTEGRATIONS,
meta: null,
apiSynced: false,
setAuthentik: (patch) =>
set((s) => ({ authentik: { ...s.authentik, ...patch } })),
setIdentityProviders: (patch) =>
set((s) => ({
identityProviders: { ...s.identityProviders, ...patch },
})),
setTwoFactor: (patch) =>
set((s) => ({ twoFactor: { ...s.twoFactor, ...patch } })),
setStorageQuotas: (patch) =>
set((s) => ({ storageQuotas: { ...s.storageQuotas, ...patch } })),
setUsageQuotas: (patch) =>
set((s) => ({ usageQuotas: { ...s.usageQuotas, ...patch } })),
setFilePolicies: (patch) =>
set((s) => ({ filePolicies: { ...s.filePolicies, ...patch } })),
setLlm: (patch) => set((s) => ({ llm: { ...s.llm, ...patch } })),
setSearch: (patch) => set((s) => ({ search: { ...s.search, ...patch } })),
setNextcloud: (patch) =>
set((s) => ({ nextcloud: { ...s.nextcloud, ...patch } })),
setMailing: (patch) =>
set((s) => ({ mailing: { ...s.mailing, ...patch } })),
setOnlyoffice: (patch) =>
set((s) => ({ onlyoffice: { ...s.onlyoffice, ...patch } })),
setAdministrators: (administrators) => set({ administrators }),
addAdministrator: (admin) =>
set((s) => ({ administrators: [...s.administrators, admin] })),
removeAdministrator: (id) =>
set((s) => ({
administrators: s.administrators.filter((a) => a.id !== id),
})),
updateAdministrator: (id, patch) =>
set((s) => ({
administrators: s.administrators.map((a) =>
a.id === id ? { ...a, ...patch } : a
),
})),
setPlugins: (plugins) => set({ plugins }),
togglePlugin: (id, enabled) =>
set((s) => ({
plugins: s.plugins.map((p) => (p.id === id ? { ...p, enabled } : p)),
})),
setIntegrations: (integrations) => set({ integrations }),
toggleIntegration: (id, enabled) =>
set((s) => ({
integrations: s.integrations.map((i) =>
i.id === id ? { ...i, enabled } : i
),
})),
hydrateFromApi: (patch, meta) =>
set((s) => ({
...s,
...patch,
meta: meta ?? s.meta,
apiSynced: true,
})),
}))