Skip to content

Commit ce47681

Browse files
Use enterprise show logic from whitelabeling
1 parent 3a356a9 commit ce47681

1 file changed

Lines changed: 120 additions & 150 deletions

File tree

apps/sim/ee/data-retention/components/data-retention-settings.tsx

Lines changed: 120 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,16 @@ import { createLogger } from '@sim/logger'
55
import { toError } from '@sim/utils/errors'
66
import { Loader2 } from 'lucide-react'
77
import { useParams } from 'next/navigation'
8-
import { Button } from '@/components/emcn'
8+
import { Button, Label } from '@/components/emcn'
99
import {
1010
Select,
1111
SelectContent,
1212
SelectItem,
1313
SelectTrigger,
1414
SelectValue,
1515
} from '@/components/ui/select'
16-
import type { PlanCategory } from '@/lib/billing/plan-helpers'
16+
import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider'
1717
import {
18-
type DataRetentionResponse,
1918
useUpdateWorkspaceRetention,
2019
useWorkspaceRetention,
2120
} from '@/ee/data-retention/hooks/data-retention'
@@ -36,48 +35,6 @@ const DAY_OPTIONS = [
3635
{ value: 'never', label: 'Forever' },
3736
] as const
3837

39-
interface RetentionFieldProps {
40-
label: string
41-
description: string
42-
value: string
43-
onChange: (value: string) => void
44-
disabled: boolean
45-
}
46-
47-
function RetentionField({ label, description, value, onChange, disabled }: RetentionFieldProps) {
48-
const standard = DAY_OPTIONS.find((o) => o.value === value)
49-
const options = standard
50-
? DAY_OPTIONS
51-
: [...DAY_OPTIONS, { value, label: `${value} days (custom)` } as const]
52-
53-
return (
54-
<div className='flex items-center justify-between py-2'>
55-
<div className='flex flex-col gap-0.5'>
56-
<span className='text-[13px] text-[var(--text-primary)]'>{label}</span>
57-
<p className='text-[12px] text-[var(--text-muted)]'>{description}</p>
58-
</div>
59-
{disabled ? (
60-
<span className='text-[13px] text-[var(--text-muted)]'>
61-
{standard?.label ?? `${value} days`}
62-
</span>
63-
) : (
64-
<Select value={value} onValueChange={onChange}>
65-
<SelectTrigger className='w-[140px] text-[13px]'>
66-
<SelectValue />
67-
</SelectTrigger>
68-
<SelectContent>
69-
{options.map((opt) => (
70-
<SelectItem key={opt.value} value={opt.value} className='text-[13px]'>
71-
{opt.label}
72-
</SelectItem>
73-
))}
74-
</SelectContent>
75-
</Select>
76-
)}
77-
</div>
78-
)
79-
}
80-
8138
function hoursToDisplayDays(hours: number | null): string {
8239
if (hours === null) return 'never'
8340
return String(Math.round(hours / 24))
@@ -88,65 +45,76 @@ function daysToHours(days: string): number | null {
8845
return Number(days) * 24
8946
}
9047

91-
const PLAN_LABELS: Record<PlanCategory, string> = {
92-
free: 'Free',
93-
pro: 'Pro',
94-
team: 'Team',
95-
enterprise: 'Enterprise',
48+
interface SettingRowProps {
49+
label: string
50+
description?: string
51+
children: React.ReactNode
9652
}
9753

98-
function LockedView({ data }: { data: DataRetentionResponse }) {
54+
function SettingRow({ label, description, children }: SettingRowProps) {
9955
return (
100-
<div className='flex flex-col gap-5'>
101-
<p className='text-[13px] text-[var(--text-muted)]'>
102-
Data retention policies control how long your workspace data is kept before automatic
103-
cleanup. Custom retention periods are available on Enterprise plans.
104-
</p>
105-
<div className='flex flex-col'>
106-
<RetentionField
107-
label='Log Retention'
108-
description='How long execution logs are kept before archival.'
109-
value={hoursToDisplayDays(data.effective.logRetentionHours)}
110-
onChange={() => {}}
111-
disabled
112-
/>
113-
<RetentionField
114-
label='Soft Deletion Cleanup'
115-
description='How long deleted resources are recoverable before permanent removal.'
116-
value={hoursToDisplayDays(data.effective.softDeleteRetentionHours)}
117-
onChange={() => {}}
118-
disabled
119-
/>
120-
<RetentionField
121-
label='Task Cleanup'
122-
description='How long before old tasks are permanently deleted.'
123-
value={hoursToDisplayDays(data.effective.taskCleanupHours)}
124-
onChange={() => {}}
125-
disabled
126-
/>
127-
</div>
128-
<p className='text-[12px] text-[var(--text-muted)]'>
129-
{PLAN_LABELS[data.plan]} plan defaults. Upgrade to Enterprise to customize retention
130-
periods.
131-
</p>
56+
<div className='flex flex-col gap-1.5'>
57+
<Label className='text-[13px] text-[var(--text-primary)]'>{label}</Label>
58+
{description && <p className='text-[12px] text-[var(--text-muted)]'>{description}</p>}
59+
{children}
13260
</div>
13361
)
13462
}
13563

136-
function EditableView({ data, workspaceId }: { data: DataRetentionResponse; workspaceId: string }) {
137-
const updateMutation = useUpdateWorkspaceRetention()
64+
function SectionTitle({ children }: { children: React.ReactNode }) {
65+
return <h3 className='mb-4 font-medium text-[15px] text-[var(--text-primary)]'>{children}</h3>
66+
}
13867

139-
const [logDays, setLogDays] = useState(hoursToDisplayDays(data.effective.logRetentionHours))
140-
const [softDeleteDays, setSoftDeleteDays] = useState(
141-
hoursToDisplayDays(data.effective.softDeleteRetentionHours)
142-
)
143-
const [taskCleanupDays, setTaskCleanupDays] = useState(
144-
hoursToDisplayDays(data.effective.taskCleanupHours)
68+
interface RetentionSelectProps {
69+
value: string
70+
onChange: (value: string) => void
71+
}
72+
73+
function RetentionSelect({ value, onChange }: RetentionSelectProps) {
74+
const standard = DAY_OPTIONS.find((o) => o.value === value)
75+
const options = standard
76+
? DAY_OPTIONS
77+
: [...DAY_OPTIONS, { value, label: `${value} days (custom)` } as const]
78+
79+
return (
80+
<Select value={value} onValueChange={onChange}>
81+
<SelectTrigger className='h-[36px] max-w-[200px] text-[13px]'>
82+
<SelectValue />
83+
</SelectTrigger>
84+
<SelectContent>
85+
{options.map((opt) => (
86+
<SelectItem key={opt.value} value={opt.value} className='text-[13px]'>
87+
{opt.label}
88+
</SelectItem>
89+
))}
90+
</SelectContent>
91+
</Select>
14592
)
93+
}
94+
95+
export function DataRetentionSettings() {
96+
const params = useParams<{ workspaceId: string }>()
97+
const workspaceId = params.workspaceId
98+
99+
const { data, isLoading } = useWorkspaceRetention(workspaceId)
100+
const { canAdmin } = useUserPermissionsContext()
101+
const updateMutation = useUpdateWorkspaceRetention()
102+
103+
const [logDays, setLogDays] = useState('')
104+
const [softDeleteDays, setSoftDeleteDays] = useState('')
105+
const [taskCleanupDays, setTaskCleanupDays] = useState('')
106+
const [formInitialized, setFormInitialized] = useState(false)
146107

147108
const [saveError, setSaveError] = useState<string | null>(null)
148109
const [saveSuccess, setSaveSuccess] = useState(false)
149110

111+
if (data && !formInitialized) {
112+
setLogDays(hoursToDisplayDays(data.effective.logRetentionHours))
113+
setSoftDeleteDays(hoursToDisplayDays(data.effective.softDeleteRetentionHours))
114+
setTaskCleanupDays(hoursToDisplayDays(data.effective.taskCleanupHours))
115+
setFormInitialized(true)
116+
}
117+
150118
const handleSave = useCallback(async () => {
151119
setSaveError(null)
152120
setSaveSuccess(false)
@@ -168,35 +136,68 @@ function EditableView({ data, workspaceId }: { data: DataRetentionResponse; work
168136
}
169137
}, [workspaceId, logDays, softDeleteDays, taskCleanupDays])
170138

171-
return (
172-
<div className='flex flex-col gap-5'>
173-
<p className='text-[13px] text-[var(--text-muted)]'>
174-
Configure how long your workspace data is retained before automatic cleanup. Values apply to
175-
all workflows in this workspace.
176-
</p>
177-
<div className='flex flex-col'>
178-
<RetentionField
179-
label='Log Retention'
180-
description='How long execution logs are kept before archival.'
181-
value={logDays}
182-
onChange={setLogDays}
183-
disabled={false}
184-
/>
185-
<RetentionField
186-
label='Soft Deletion Cleanup'
187-
description='How long deleted resources are recoverable before permanent removal.'
188-
value={softDeleteDays}
189-
onChange={setSoftDeleteDays}
190-
disabled={false}
191-
/>
192-
<RetentionField
193-
label='Task Cleanup'
194-
description='How long before old tasks are permanently deleted.'
195-
value={taskCleanupDays}
196-
onChange={setTaskCleanupDays}
197-
disabled={false}
198-
/>
139+
if (isLoading) {
140+
return (
141+
<div className='flex flex-col gap-8'>
142+
{[...Array(3)].map((_, i) => (
143+
<div key={i} className='flex flex-col gap-3'>
144+
<div className='h-4 w-32 animate-pulse rounded bg-[var(--surface-3)]' />
145+
<div className='h-9 w-full animate-pulse rounded-lg bg-[var(--surface-3)]' />
146+
</div>
147+
))}
148+
</div>
149+
)
150+
}
151+
152+
if (!data) {
153+
return (
154+
<div className='flex h-full items-center justify-center text-[var(--text-muted)] text-sm'>
155+
Failed to load data retention settings.
156+
</div>
157+
)
158+
}
159+
160+
if (!data.isEnterprise) {
161+
return (
162+
<div className='flex h-full items-center justify-center text-[var(--text-muted)] text-sm'>
163+
Data retention is available on Enterprise plans only.
199164
</div>
165+
)
166+
}
167+
168+
if (!canAdmin) {
169+
return (
170+
<div className='flex h-full items-center justify-center text-[var(--text-muted)] text-sm'>
171+
Only workspace admins can configure data retention settings.
172+
</div>
173+
)
174+
}
175+
176+
return (
177+
<div className='flex flex-col gap-8'>
178+
<section>
179+
<SectionTitle>Retention Periods</SectionTitle>
180+
<div className='flex flex-col gap-5'>
181+
<SettingRow
182+
label='Log retention'
183+
description='How long execution logs are kept before they are permanently deleted.'
184+
>
185+
<RetentionSelect value={logDays} onChange={setLogDays} />
186+
</SettingRow>
187+
<SettingRow
188+
label='Soft deletion cleanup'
189+
description='How long deleted resources remain recoverable before they are permanently removed.'
190+
>
191+
<RetentionSelect value={softDeleteDays} onChange={setSoftDeleteDays} />
192+
</SettingRow>
193+
<SettingRow
194+
label='Task cleanup'
195+
description='How long copilot chats, runs, and inbox tasks are kept before they are permanently deleted.'
196+
>
197+
<RetentionSelect value={taskCleanupDays} onChange={setTaskCleanupDays} />
198+
</SettingRow>
199+
</div>
200+
</section>
200201

201202
<div className='flex items-center gap-3'>
202203
<Button onClick={handleSave} disabled={updateMutation.isPending} className='text-[13px]'>
@@ -217,34 +218,3 @@ function EditableView({ data, workspaceId }: { data: DataRetentionResponse; work
217218
</div>
218219
)
219220
}
220-
221-
export function DataRetentionSettings() {
222-
const params = useParams()
223-
const workspaceId = params.workspaceId as string
224-
225-
const { data, isLoading, error } = useWorkspaceRetention(workspaceId)
226-
227-
if (isLoading) {
228-
return (
229-
<div className='flex flex-col gap-4'>
230-
{[...Array(3)].map((_, i) => (
231-
<div key={i} className='h-[40px] w-full animate-pulse rounded bg-[var(--surface-3)]' />
232-
))}
233-
</div>
234-
)
235-
}
236-
237-
if (error || !data) {
238-
return (
239-
<div className='text-[13px] text-[var(--text-muted)]'>
240-
Failed to load data retention settings.
241-
</div>
242-
)
243-
}
244-
245-
if (!data.isEnterprise) {
246-
return <LockedView data={data} />
247-
}
248-
249-
return <EditableView data={data} workspaceId={workspaceId} />
250-
}

0 commit comments

Comments
 (0)