improvement(settings): persistent layout + locked-down header API by waleedlatif1 · Pull Request #5278 · simstudioai/sim · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 44 additions & 30 deletions .claude/rules/sim-settings-pages.md
18 changes: 18 additions & 0 deletions apps/sim/app/workspace/[workspaceId]/settings/[section]/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import {
SettingsHeaderProvider,
SettingsHeaderShell,
} from '@/app/workspace/[workspaceId]/settings/components/settings-header/settings-header'

/**
* Persistent chrome for the settings panel pages. The header bar, title,
* description, scroll region, and centered column live in the shell and stay
* mounted across section navigation — only the body swaps. Scoped to `[section]`
* so detail routes (e.g. `secrets/[credentialId]`) keep their own chrome.
*/
export default function SettingsSectionLayout({ children }: { children: React.ReactNode }) {
return (
<SettingsHeaderProvider>
<SettingsHeaderShell>{children}</SettingsHeaderShell>
Comment thread
waleedlatif1 marked this conversation as resolved.
</SettingsHeaderProvider>
Comment thread
waleedlatif1 marked this conversation as resolved.
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -129,30 +129,28 @@ export function SettingsPage({ section }: SettingsPageProps) {

return (
<SettingsSectionProvider section={effectiveSection}>
<div className='flex h-full flex-col'>
{effectiveSection === 'general' && <General />}
{effectiveSection === 'secrets' && <Secrets />}
{effectiveSection === 'credential-sets' && <CredentialSets />}
{effectiveSection === 'access-control' && <AccessControl />}
{effectiveSection === 'audit-logs' && <AuditLogs />}
{effectiveSection === 'apikeys' && <ApiKeys />}
{isBillingEnabled && effectiveSection === 'billing' && <Billing />}
{effectiveSection === 'teammates' && <Teammates />}
{isBillingEnabled && effectiveSection === 'organization' && <TeamManagement />}
{effectiveSection === 'sso' && <SSO />}
{effectiveSection === 'data-retention' && <DataRetentionSettings />}
{effectiveSection === 'data-drains' && <DataDrainsSettings />}
{effectiveSection === 'whitelabeling' && <WhitelabelingSettings />}
{effectiveSection === 'byok' && <BYOK />}
{effectiveSection === 'copilot' && <Copilot />}
{effectiveSection === 'mcp' && <MCP />}
{effectiveSection === 'custom-tools' && <CustomTools />}
{effectiveSection === 'workflow-mcp-servers' && <WorkflowMcpServers />}
{effectiveSection === 'inbox' && <Inbox />}
{effectiveSection === 'recently-deleted' && <RecentlyDeleted />}
{effectiveSection === 'admin' && <Admin />}
{effectiveSection === 'mothership' && <Mothership />}
</div>
{effectiveSection === 'general' && <General />}
{effectiveSection === 'secrets' && <Secrets />}
{effectiveSection === 'credential-sets' && <CredentialSets />}
{effectiveSection === 'access-control' && <AccessControl />}
{effectiveSection === 'audit-logs' && <AuditLogs />}
{effectiveSection === 'apikeys' && <ApiKeys />}
{isBillingEnabled && effectiveSection === 'billing' && <Billing />}
{effectiveSection === 'teammates' && <Teammates />}
{isBillingEnabled && effectiveSection === 'organization' && <TeamManagement />}
{effectiveSection === 'sso' && <SSO />}
{effectiveSection === 'data-retention' && <DataRetentionSettings />}
{effectiveSection === 'data-drains' && <DataDrainsSettings />}
{effectiveSection === 'whitelabeling' && <WhitelabelingSettings />}
{effectiveSection === 'byok' && <BYOK />}
{effectiveSection === 'copilot' && <Copilot />}
{effectiveSection === 'mcp' && <MCP />}
{effectiveSection === 'custom-tools' && <CustomTools />}
{effectiveSection === 'workflow-mcp-servers' && <WorkflowMcpServers />}
{effectiveSection === 'inbox' && <Inbox />}
{effectiveSection === 'recently-deleted' && <RecentlyDeleted />}
{effectiveSection === 'admin' && <Admin />}
{effectiveSection === 'mothership' && <Mothership />}
</SettingsSectionProvider>
)
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client'

import { useMemo, useState } from 'react'
import { Chip, ChipConfirmModal, Switch, Tooltip, toast } from '@sim/emcn'
import { ChipConfirmModal, Switch, Tooltip, toast } from '@sim/emcn'
import { createLogger } from '@sim/logger'
import { formatDate } from '@sim/utils/formatting'
import { Info, Plus } from 'lucide-react'
Expand All @@ -10,6 +10,7 @@ import { useSession } from '@/lib/auth/auth-client'
import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider'
import { RowActionsMenu } from '@/app/workspace/[workspaceId]/settings/components/row-actions-menu'
import { SettingsEmptyState } from '@/app/workspace/[workspaceId]/settings/components/settings-empty-state'
import type { SettingsAction } from '@/app/workspace/[workspaceId]/settings/components/settings-header/settings-header'
import { SettingsPanel } from '@/app/workspace/[workspaceId]/settings/components/settings-panel'
import { SettingsSection } from '@/app/workspace/[workspaceId]/settings/components/settings-section/settings-section'
import {
Expand Down Expand Up @@ -132,6 +133,19 @@ export function ApiKeys() {
return formatDate(new Date(dateString))
}

const actions: SettingsAction[] = [
{
text: 'Create API key',
icon: Plus,
variant: 'primary',
onSelect: () => {
if (createButtonDisabled) return
setIsCreateDialogOpen(true)
},
disabled: createButtonDisabled,
},
]

return (
<>
<SettingsPanel
Expand All @@ -140,22 +154,10 @@ export function ApiKeys() {
onChange: setSearchTerm,
placeholder: 'Search API keys...',
}}
actions={
<Chip
leftIcon={Plus}
variant='primary'
onClick={() => {
if (createButtonDisabled) return
setIsCreateDialogOpen(true)
}}
disabled={createButtonDisabled}
>
Create API Key
</Chip>
}
actions={actions}
>
{isLoading ? null : personalKeys.length === 0 && workspaceKeys.length === 0 ? (
<SettingsEmptyState>Click "Create API Key" above to get started</SettingsEmptyState>
<SettingsEmptyState>Click "Create API key" above to get started</SettingsEmptyState>
) : (
<div className='flex flex-col gap-6'>
{!searchTerm.trim() ? (
Expand Down
Loading
Loading