Skip to content

Commit 9c898ae

Browse files
committed
Updates
1 parent f7b803a commit 9c898ae

12 files changed

Lines changed: 15856 additions & 78 deletions

File tree

apps/sim/app/api/users/me/settings/route.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const defaultSettings = {
2020
billingUsageNotificationsEnabled: true,
2121
showTrainingControls: false,
2222
superUserModeEnabled: false,
23-
mothershipEnvironment: 'prod',
23+
mothershipEnvironment: 'default',
2424
errorNotificationsEnabled: true,
2525
snapToGridSize: 0,
2626
showActionBar: true,
@@ -57,7 +57,7 @@ export const GET = withRouteHandler(async () => {
5757
billingUsageNotificationsEnabled: userSettings.billingUsageNotificationsEnabled ?? true,
5858
showTrainingControls: userSettings.showTrainingControls ?? false,
5959
superUserModeEnabled: userSettings.superUserModeEnabled ?? false,
60-
mothershipEnvironment: userSettings.mothershipEnvironment ?? 'prod',
60+
mothershipEnvironment: userSettings.mothershipEnvironment ?? 'default',
6161
errorNotificationsEnabled: userSettings.errorNotificationsEnabled ?? true,
6262
snapToGridSize: userSettings.snapToGridSize ?? 0,
6363
showActionBar: userSettings.showActionBar ?? true,

apps/sim/app/workspace/[workspaceId]/settings/[section]/settings.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,13 @@ const Admin = dynamic(
146146
import('@/app/workspace/[workspaceId]/settings/components/admin/admin').then((m) => m.Admin),
147147
{ loading: () => <AdminSkeleton /> }
148148
)
149+
const Mothership = dynamic(
150+
() =>
151+
import('@/app/workspace/[workspaceId]/settings/components/mothership/mothership').then(
152+
(m) => m.Mothership
153+
),
154+
{ loading: () => <SettingsSectionSkeleton /> }
155+
)
149156
const RecentlyDeleted = dynamic(
150157
() =>
151158
import(
@@ -202,11 +209,9 @@ export function SettingsPage({ section }: SettingsPageProps) {
202209
? 'general'
203210
: section === 'admin' && !sessionLoading && !isAdminRole
204211
? 'general'
205-
: section === 'mothership' && !sessionLoading && isAdminRole
206-
? 'admin'
207-
: section === 'mothership' && !sessionLoading && !isAdminRole
208-
? 'general'
209-
: section
212+
: section === 'mothership' && !sessionLoading && !isAdminRole
213+
? 'general'
214+
: section
210215

211216
const label =
212217
allNavigationItems.find((item) => item.id === effectiveSection)?.label ?? effectiveSection
@@ -247,6 +252,7 @@ export function SettingsPage({ section }: SettingsPageProps) {
247252
{effectiveSection === 'inbox' && <Inbox />}
248253
{effectiveSection === 'recently-deleted' && <RecentlyDeleted />}
249254
{effectiveSection === 'admin' && <Admin />}
255+
{effectiveSection === 'mothership' && <Mothership />}
250256
</div>
251257
)
252258
}

apps/sim/app/workspace/[workspaceId]/settings/components/admin/admin.tsx

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,15 @@
22

33
import { useCallback, useMemo, useState } from 'react'
44
import { useParams } from 'next/navigation'
5-
import { Badge, Button, Input as EmcnInput, Label, Skeleton, Switch } from '@/components/emcn'
5+
import {
6+
Badge,
7+
Button,
8+
Combobox,
9+
Input as EmcnInput,
10+
Label,
11+
Skeleton,
12+
Switch,
13+
} from '@/components/emcn'
614
import type { MothershipEnvironment } from '@/lib/api/contracts'
715
import { useSession } from '@/lib/auth/auth-client'
816
import { cn } from '@/lib/core/utils/cn'
@@ -18,10 +26,11 @@ import { useImportWorkflow } from '@/hooks/queries/workflows'
1826

1927
const PAGE_SIZE = 20 as const
2028

21-
const ENV_OPTIONS: { id: MothershipEnvironment; label: string }[] = [
22-
{ id: 'dev', label: 'Dev' },
23-
{ id: 'staging', label: 'Staging' },
24-
{ id: 'prod', label: 'Prod' },
29+
const MOTHERSHIP_ENV_OPTIONS: { value: MothershipEnvironment; label: string }[] = [
30+
{ value: 'default', label: 'Default' },
31+
{ value: 'dev', label: 'Dev' },
32+
{ value: 'staging', label: 'Staging' },
33+
{ value: 'prod', label: 'Prod' },
2534
]
2635

2736
export function Admin() {
@@ -154,26 +163,22 @@ export function Admin() {
154163
<div className='flex flex-col gap-1'>
155164
<Label className='text-[var(--text-primary)] text-sm'>Mothership Environment</Label>
156165
<p className='text-[var(--text-secondary)] text-xs'>
157-
Controls which Copilot backend this admin session talks to.
166+
Default uses the configured Sim agent URL.
158167
</p>
159168
</div>
160-
<div className='flex gap-1'>
161-
{ENV_OPTIONS.map((opt) => (
162-
<button
163-
key={opt.id}
164-
type='button'
165-
onClick={() => handleMothershipEnvironmentChange(opt.id)}
166-
disabled={updateSetting.isPending}
167-
className={cn(
168-
'rounded-md px-3 py-1 font-medium text-sm transition-colors',
169-
(settings?.mothershipEnvironment ?? 'prod') === opt.id
170-
? 'bg-[var(--surface-hover)] text-[var(--text-primary)]'
171-
: 'text-[var(--text-tertiary)] hover-hover:hover:text-[var(--text-secondary)]'
172-
)}
173-
>
174-
{opt.label}
175-
</button>
176-
))}
169+
<div className='w-[160px]'>
170+
<Combobox
171+
size='sm'
172+
align='end'
173+
dropdownWidth={160}
174+
value={settings?.mothershipEnvironment ?? 'default'}
175+
onChange={(value) =>
176+
handleMothershipEnvironmentChange(value as MothershipEnvironment)
177+
}
178+
placeholder='Select environment'
179+
disabled={updateSetting.isPending}
180+
options={MOTHERSHIP_ENV_OPTIONS}
181+
/>
177182
</div>
178183
</div>
179184
)}

apps/sim/app/workspace/[workspaceId]/settings/components/mothership/mothership.tsx

Lines changed: 5 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import { useCallback, useMemo, useState } from 'react'
44
import { Badge, Button, Input as EmcnInput, Label, Skeleton } from '@/components/emcn'
55
import { cn } from '@/lib/core/utils/cn'
6-
import { useGeneralSettings, useUpdateGeneralSetting } from '@/hooks/queries/general-settings'
76
import {
87
type MothershipEnv,
98
useGenerateLicense,
@@ -63,58 +62,22 @@ function SectionLabel({ children }: { children: React.ReactNode }) {
6362

6463
export function Mothership() {
6564
const [activeTab, setActiveTab] = useState<Tab>('overview')
66-
const { data: settings, isLoading: settingsLoading } = useGeneralSettings()
67-
const updateSetting = useUpdateGeneralSetting()
68-
const environment = settings?.mothershipEnvironment ?? 'prod'
65+
const [environment, setEnvironment] = useState<MothershipEnv>('dev')
6966
const defaults = useMemo(() => defaultTimeRange(), [])
7067
const [start, setStart] = useState(defaults.start)
7168
const [end, setEnd] = useState(defaults.end)
7269

73-
const handleEnvironmentChange = useCallback(
74-
async (nextEnvironment: MothershipEnv) => {
75-
if (nextEnvironment !== settings?.mothershipEnvironment && !updateSetting.isPending) {
76-
await updateSetting.mutateAsync({
77-
key: 'mothershipEnvironment',
78-
value: nextEnvironment,
79-
})
80-
}
81-
},
82-
[settings?.mothershipEnvironment, updateSetting]
83-
)
84-
85-
if (settingsLoading) {
86-
return (
87-
<div className='flex h-full flex-col gap-5'>
88-
<Skeleton className='h-[32px] w-[320px] rounded-md' />
89-
<Skeleton className='h-[40px] w-full rounded-md' />
90-
<Skeleton className='h-[120px] w-full rounded-md' />
91-
</div>
92-
)
93-
}
94-
95-
if (!settings?.superUserModeEnabled) {
96-
return (
97-
<div className='flex h-full flex-col gap-3'>
98-
<p className='font-medium text-[var(--text-primary)] text-sm'>Super admin mode is off</p>
99-
<p className='text-[var(--text-secondary)] text-sm'>
100-
Enable Super admin mode in Admin settings to view Mothership controls and change the
101-
Mothership environment.
102-
</p>
103-
</div>
104-
)
105-
}
106-
10770
return (
10871
<div className='flex h-full flex-col gap-5'>
109-
<div className='flex items-center gap-3'>
110-
<Label className='text-[var(--text-secondary)] text-sm'>Mothership Environment</Label>
72+
{/* Environment selector */}
73+
<div className='flex items-center gap-2'>
74+
<Label className='text-[var(--text-secondary)] text-sm'>Environment</Label>
11175
<div className='flex gap-1'>
11276
{ENV_OPTIONS.map((opt) => (
11377
<button
11478
key={opt.id}
11579
type='button'
116-
onClick={() => handleEnvironmentChange(opt.id)}
117-
disabled={updateSetting.isPending}
80+
onClick={() => setEnvironment(opt.id)}
11881
className={cn(
11982
'rounded-md px-3 py-1 font-medium text-sm transition-colors',
12083
environment === opt.id

apps/sim/app/workspace/[workspaceId]/settings/navigation.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,4 +218,11 @@ export const allNavigationItems: NavigationItem[] = [
218218
section: 'superuser',
219219
requiresAdminRole: true,
220220
},
221+
{
222+
id: 'mothership',
223+
label: 'Mothership',
224+
icon: Server,
225+
section: 'superuser',
226+
requiresAdminRole: true,
227+
},
221228
]

apps/sim/hooks/queries/mothership-admin.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { keepPreviousData, useMutation, useQuery } from '@tanstack/react-query'
22

3-
export type MothershipEnv = 'dev' | 'staging' | 'prod'
3+
export type MothershipEnv = 'default' | 'dev' | 'staging' | 'prod'
44

55
const BASE = '/api/admin/mothership'
66

apps/sim/lib/api/contracts/user.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export const userSettingsEmailPreferencesSchema = z.object({
6161
unsubscribeNotifications: z.boolean().optional(),
6262
})
6363

64-
export const mothershipEnvironmentSchema = z.enum(['dev', 'staging', 'prod'])
64+
export const mothershipEnvironmentSchema = z.enum(['default', 'dev', 'staging', 'prod'])
6565
export type MothershipEnvironment = z.infer<typeof mothershipEnvironmentSchema>
6666

6767
export const userSettingsSchema = z.object({
@@ -72,7 +72,7 @@ export const userSettingsSchema = z.object({
7272
billingUsageNotificationsEnabled: z.boolean().default(true),
7373
showTrainingControls: z.boolean().default(false),
7474
superUserModeEnabled: z.boolean().default(false),
75-
mothershipEnvironment: mothershipEnvironmentSchema.default('prod'),
75+
mothershipEnvironment: mothershipEnvironmentSchema.default('default'),
7676
errorNotificationsEnabled: z.boolean().default(true),
7777
snapToGridSize: z.number().min(0).max(50).default(0),
7878
showActionBar: z.boolean().default(true),

apps/sim/lib/copilot/server/agent-url.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ export interface GetMothershipBaseURLOptions {
1111
fallbackUrl?: string | null
1212
}
1313

14-
const ENVIRONMENT_URLS: Record<MothershipEnvironment, string | undefined> = {
14+
type ConcreteMothershipEnvironment = Exclude<MothershipEnvironment, 'default'>
15+
16+
const ENVIRONMENT_URLS: Record<ConcreteMothershipEnvironment, string | undefined> = {
1517
// env vars
1618
dev: env.COPILOT_DEV_URL,
1719
staging: env.COPILOT_STAGING_URL,
@@ -24,6 +26,7 @@ function normalizeUrl(url: string | undefined): string | null {
2426
}
2527

2628
function getConfiguredEnvironmentUrl(environment: MothershipEnvironment): string | null {
29+
if (environment === 'default') return null
2730
return normalizeUrl(ENVIRONMENT_URLS[environment])
2831
}
2932

@@ -59,7 +62,7 @@ export async function getMothershipBaseURL(
5962
if (!effectiveSuperUser) return defaultUrl
6063

6164
const parsedEnvironment = mothershipEnvironmentSchema.safeParse(row.mothershipEnvironment)
62-
const environment = parsedEnvironment.success ? parsedEnvironment.data : 'prod'
65+
const environment = parsedEnvironment.success ? parsedEnvironment.data : 'default'
6366

6467
return getConfiguredEnvironmentUrl(environment) ?? defaultUrl
6568
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ALTER TABLE "settings" ALTER COLUMN "mothership_environment" SET DEFAULT 'default';

0 commit comments

Comments
 (0)