Skip to content

Commit 694b530

Browse files
chore: client and server components (#3716)
1 parent 91a0a49 commit 694b530

File tree

25 files changed

+657
-687
lines changed

25 files changed

+657
-687
lines changed

apps/sim/app/(auth)/components/status-page-layout.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
'use client'
2-
31
import type { ReactNode } from 'react'
42
import AuthBackground from '@/app/(auth)/components/auth-background'
53
import Navbar from '@/app/(home)/components/navbar/navbar'
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
'use client'
2+
3+
import { useRef, useState } from 'react'
4+
import { motion, useInView } from 'framer-motion'
5+
import { PROVIDER_DEFINITIONS } from '@/providers/models'
6+
7+
interface PermissionFeature {
8+
name: string
9+
key: string
10+
defaultEnabled: boolean
11+
providerId?: string
12+
}
13+
14+
interface PermissionCategory {
15+
label: string
16+
color: string
17+
features: PermissionFeature[]
18+
}
19+
20+
const PERMISSION_CATEGORIES: PermissionCategory[] = [
21+
{
22+
label: 'Providers',
23+
color: '#FA4EDF',
24+
features: [
25+
{ key: 'openai', name: 'OpenAI', defaultEnabled: true, providerId: 'openai' },
26+
{ key: 'anthropic', name: 'Anthropic', defaultEnabled: true, providerId: 'anthropic' },
27+
{ key: 'google', name: 'Google', defaultEnabled: false, providerId: 'google' },
28+
{ key: 'xai', name: 'xAI', defaultEnabled: true, providerId: 'xai' },
29+
],
30+
},
31+
{
32+
label: 'Workspace',
33+
color: '#2ABBF8',
34+
features: [
35+
{ key: 'knowledge-base', name: 'Knowledge Base', defaultEnabled: true },
36+
{ key: 'tables', name: 'Tables', defaultEnabled: true },
37+
{ key: 'copilot', name: 'Copilot', defaultEnabled: false },
38+
{ key: 'environment', name: 'Environment', defaultEnabled: false },
39+
],
40+
},
41+
{
42+
label: 'Tools',
43+
color: '#33C482',
44+
features: [
45+
{ key: 'mcp-tools', name: 'MCP Tools', defaultEnabled: true },
46+
{ key: 'custom-tools', name: 'Custom Tools', defaultEnabled: false },
47+
{ key: 'skills', name: 'Skills', defaultEnabled: true },
48+
{ key: 'invitations', name: 'Invitations', defaultEnabled: true },
49+
],
50+
},
51+
]
52+
53+
const INITIAL_ACCESS_STATE = Object.fromEntries(
54+
PERMISSION_CATEGORIES.flatMap((category) =>
55+
category.features.map((feature) => [feature.key, feature.defaultEnabled])
56+
)
57+
)
58+
59+
function CheckboxIcon({ checked, color }: { checked: boolean; color: string }) {
60+
return (
61+
<div
62+
className='h-[6px] w-[6px] shrink-0 rounded-full transition-colors duration-200'
63+
style={{
64+
backgroundColor: checked ? color : 'transparent',
65+
border: checked ? 'none' : '1.5px solid #3A3A3A',
66+
}}
67+
/>
68+
)
69+
}
70+
71+
function ProviderPreviewIcon({ providerId }: { providerId?: string }) {
72+
if (!providerId) return null
73+
74+
const ProviderIcon = PROVIDER_DEFINITIONS[providerId]?.icon
75+
if (!ProviderIcon) return null
76+
77+
return (
78+
<div className='relative flex h-[14px] w-[14px] shrink-0 items-center justify-center opacity-50 brightness-0 invert'>
79+
<ProviderIcon className='!h-[14px] !w-[14px]' />
80+
</div>
81+
)
82+
}
83+
84+
export function AccessControlPanel() {
85+
const ref = useRef(null)
86+
const isInView = useInView(ref, { once: true, margin: '-40px' })
87+
const [accessState, setAccessState] = useState<Record<string, boolean>>(INITIAL_ACCESS_STATE)
88+
89+
return (
90+
<div ref={ref}>
91+
<div className='lg:hidden'>
92+
{PERMISSION_CATEGORIES.map((category, catIdx) => {
93+
const offsetBefore = PERMISSION_CATEGORIES.slice(0, catIdx).reduce(
94+
(sum, c) => sum + c.features.length,
95+
0
96+
)
97+
98+
return (
99+
<div key={category.label} className={catIdx > 0 ? 'mt-4' : ''}>
100+
<span className='font-[430] font-season text-[#F6F6F6]/30 text-[10px] uppercase leading-none tracking-[0.08em]'>
101+
{category.label}
102+
</span>
103+
<div className='mt-[8px] grid grid-cols-2 gap-x-4 gap-y-[8px]'>
104+
{category.features.map((feature, featIdx) => {
105+
const enabled = accessState[feature.key]
106+
107+
return (
108+
<motion.div
109+
key={feature.key}
110+
className='flex cursor-pointer items-center gap-[8px] rounded-[4px] py-[2px]'
111+
initial={{ opacity: 0, x: -6 }}
112+
animate={isInView ? { opacity: 1, x: 0 } : {}}
113+
transition={{
114+
delay: 0.05 + (offsetBefore + featIdx) * 0.04,
115+
duration: 0.3,
116+
}}
117+
onClick={() =>
118+
setAccessState((prev) => ({ ...prev, [feature.key]: !prev[feature.key] }))
119+
}
120+
whileTap={{ scale: 0.98 }}
121+
>
122+
<CheckboxIcon checked={enabled} color={category.color} />
123+
<ProviderPreviewIcon providerId={feature.providerId} />
124+
<span
125+
className='truncate font-[430] font-season text-[13px] leading-none tracking-[0.02em]'
126+
style={{ color: enabled ? '#F6F6F6AA' : '#F6F6F640' }}
127+
>
128+
{feature.name}
129+
</span>
130+
</motion.div>
131+
)
132+
})}
133+
</div>
134+
</div>
135+
)
136+
})}
137+
</div>
138+
139+
{/* Desktop -- categorized grid */}
140+
<div className='hidden lg:block'>
141+
{PERMISSION_CATEGORIES.map((category, catIdx) => (
142+
<div key={category.label} className={catIdx > 0 ? 'mt-4' : ''}>
143+
<span className='font-[430] font-season text-[#F6F6F6]/30 text-[10px] uppercase leading-none tracking-[0.08em]'>
144+
{category.label}
145+
</span>
146+
<div className='mt-[8px] grid grid-cols-2 gap-x-4 gap-y-[8px]'>
147+
{category.features.map((feature, featIdx) => {
148+
const enabled = accessState[feature.key]
149+
const currentIndex =
150+
PERMISSION_CATEGORIES.slice(0, catIdx).reduce(
151+
(sum, c) => sum + c.features.length,
152+
0
153+
) + featIdx
154+
155+
return (
156+
<motion.div
157+
key={feature.key}
158+
className='flex cursor-pointer items-center gap-[8px] rounded-[4px] py-[2px]'
159+
initial={{ opacity: 0, x: -6 }}
160+
animate={isInView ? { opacity: 1, x: 0 } : {}}
161+
transition={{
162+
delay: 0.1 + currentIndex * 0.04,
163+
duration: 0.3,
164+
ease: [0.25, 0.46, 0.45, 0.94],
165+
}}
166+
onClick={() =>
167+
setAccessState((prev) => ({ ...prev, [feature.key]: !prev[feature.key] }))
168+
}
169+
whileTap={{ scale: 0.98 }}
170+
>
171+
<CheckboxIcon checked={enabled} color={category.color} />
172+
<ProviderPreviewIcon providerId={feature.providerId} />
173+
<span
174+
className='truncate font-[430] font-season text-[11px] leading-none tracking-[0.02em] transition-opacity duration-200'
175+
style={{ color: enabled ? '#F6F6F6AA' : '#F6F6F640' }}
176+
>
177+
{feature.name}
178+
</span>
179+
</motion.div>
180+
)
181+
})}
182+
</div>
183+
</div>
184+
))}
185+
</div>
186+
</div>
187+
)
188+
}

0 commit comments

Comments
 (0)