ultisuite-client/components/admin/settings/sections/quotas-section.tsx
R3D347HR4Y 9ea2d3325d
Some checks are pending
E2E / Playwright e2e (push) Waiting to run
feat(auth): enhance authentication flows with embedded support and UI improvements
- Updated login and signup components to utilize AuthCard for better user experience during redirection.
- Introduced AuthentikEmbedDialog for seamless integration of Authentik's identity portal within the application.
- Enhanced password recovery and signup flows with dynamic theme handling and improved loading states.
- Refactored existing components to streamline authentication processes and improve maintainability.
2026-06-21 00:12:45 +02:00

198 lines
6.0 KiB
TypeScript

"use client"
import Link from "next/link"
import { AutomationTabMasonry } from "@/components/gmail/settings/automation/automation-tab-masonry"
import {
SettingsCard,
SettingsField,
SettingsGrid,
} from "@/components/settings/settings-kit"
import { OrgSettingsSection } from "@/components/admin/settings/org-settings-form"
import { useOrgSettingsStore } from "@/lib/admin-settings/org-settings-store"
import { Button } from "@/components/ui/button"
import {
InputGroup,
InputGroupAddon,
InputGroupInput,
InputGroupText,
} from "@/components/ui/input-group"
import { cn } from "@/lib/utils"
export function QuotasSection() {
const storageQuotas = useOrgSettingsStore((s) => s.storageQuotas)
const setStorageQuotas = useOrgSettingsStore((s) => s.setStorageQuotas)
const usageQuotas = useOrgSettingsStore((s) => s.usageQuotas)
const setUsageQuotas = useOrgSettingsStore((s) => s.setUsageQuotas)
return (
<OrgSettingsSection
title="Quotas"
description="Limites de stockage et d'usage appliquées par défaut aux comptes de l'organisation."
policySection={["storage_quotas", "usage_quotas"]}
>
<AutomationTabMasonry columns={2}>
<SettingsCard
title="Stockage par défaut"
description="Mail, drive et photos. Les quotas individuels se gèrent depuis la fiche utilisateur."
>
<SettingsGrid columns={2} className="sm:grid-cols-3">
<QuotaInput
label="Mail"
unit="Go"
value={storageQuotas.default_mail_gib}
onChange={(v) => setStorageQuotas({ default_mail_gib: v })}
/>
<QuotaInput
label="Drive"
unit="Go"
value={storageQuotas.default_drive_gib}
onChange={(v) => setStorageQuotas({ default_drive_gib: v })}
/>
<QuotaInput
label="Photos"
unit="Go"
value={storageQuotas.default_photos_gib}
onChange={(v) => setStorageQuotas({ default_photos_gib: v })}
/>
</SettingsGrid>
<SettingsNumberField
label="Seuil d'alerte"
unit="%"
min={50}
max={100}
fallback={90}
value={storageQuotas.warn_threshold_pct}
onChange={(v) => setStorageQuotas({ warn_threshold_pct: v })}
/>
<Button asChild variant="outline" size="sm">
<Link href="/admin/settings/users">Gérer les quotas par utilisateur</Link>
</Button>
</SettingsCard>
<SettingsCard
title="Intelligence artificielle"
description="Plafonds par utilisateur (clés org) : usage quotidien et mensuel raisonnable pour une PME."
>
<SettingsGrid columns={2}>
<SettingsNumberField
label="Plafond journalier"
unit="€"
step={0.5}
value={usageQuotas.llm_daily_cost_limit_eur}
onChange={(v) => setUsageQuotas({ llm_daily_cost_limit_eur: v })}
/>
<SettingsNumberField
label="Plafond mensuel"
unit="€"
step={1}
value={usageQuotas.llm_monthly_cost_limit_eur}
onChange={(v) => setUsageQuotas({ llm_monthly_cost_limit_eur: v })}
/>
</SettingsGrid>
<SettingsNumberField
label="Seuil d'alerte"
unit="%"
min={50}
max={100}
fallback={80}
value={usageQuotas.llm_cost_warn_threshold_pct}
onChange={(v) => setUsageQuotas({ llm_cost_warn_threshold_pct: v })}
/>
<Button asChild variant="outline" size="sm">
<Link href="/admin/settings/ai-usage">Voir la consommation IA</Link>
</Button>
</SettingsCard>
<SettingsCard
title="Recherche et automatisations"
description="Recherche web, tokens API et webhooks par utilisateur."
>
<SettingsGrid columns={2} className="lg:grid-cols-1 xl:grid-cols-3">
<SettingsNumberField
label="Recherches web"
unit="/ jour"
value={usageQuotas.search_requests_per_day}
onChange={(v) => setUsageQuotas({ search_requests_per_day: v })}
/>
<SettingsNumberField
label="Tokens API"
unit="/ utilisateur"
value={usageQuotas.max_api_tokens_per_user}
onChange={(v) => setUsageQuotas({ max_api_tokens_per_user: v })}
/>
<SettingsNumberField
label="Webhooks"
unit="/ utilisateur"
value={usageQuotas.max_webhooks_per_user}
onChange={(v) => setUsageQuotas({ max_webhooks_per_user: v })}
/>
</SettingsGrid>
</SettingsCard>
</AutomationTabMasonry>
</OrgSettingsSection>
)
}
function QuotaInput({
label,
unit,
value,
onChange,
}: {
label: string
unit: string
value: number
onChange: (v: number) => void
}) {
return (
<SettingsNumberField
label={label}
unit={unit}
step={0.5}
value={value}
onChange={onChange}
/>
)
}
function SettingsNumberField({
label,
unit,
value,
onChange,
min = 0,
max,
step,
fallback = 0,
className,
}: {
label: string
unit: string
value: number
onChange: (v: number) => void
min?: number
max?: number
step?: number
fallback?: number
className?: string
}) {
return (
<SettingsField label={label}>
<InputGroup className={cn("w-fit max-w-full", className)}>
<InputGroupInput
type="number"
min={min}
max={max}
step={step}
value={value}
className="w-20 flex-none tabular-nums"
onChange={(e) => onChange(Number(e.target.value) || fallback)}
/>
<InputGroupAddon align="inline-end">
<InputGroupText>{unit}</InputGroupText>
</InputGroupAddon>
</InputGroup>
</SettingsField>
)
}