Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
5cd02a6
improvement(platform): consolidate organization integrations
emir-karabeg Nov 6, 2026
a824d10
improvement(platform): expand integration catalog and credential mana…
emir-karabeg Nov 6, 2026
1666511
improvement(platform): consolidate one shared local preview
emir-karabeg Nov 6, 2026
cdccb5b
improvement(platform): retain latest integration spacing alignment
emir-karabeg Nov 6, 2026
9b6c3ab
feat(platform): consolidate controls and redesign integration details
emir-karabeg Nov 6, 2026
d21b2ad
feat(platform): refine integration ideas and shared control behavior
emir-karabeg Nov 6, 2026
6d4fe36
fix(platform): distinguish reconnect dialog identity
emir-karabeg Nov 6, 2026
67d6a34
fix(platform): commit detail history before presentation
emir-karabeg Nov 6, 2026
39a59f2
feat(platform): consolidate credential access tables and integration …
emir-karabeg Nov 6, 2026
b771f91
fix(platform): retain credential identity across detail tabs
emir-karabeg Nov 6, 2026
8215c09
test(platform): remove obsolete connected app description assertion
emir-karabeg Nov 6, 2026
eba54cd
test(platform): tolerate shared preview worker connection resets
emir-karabeg Nov 6, 2026
9896c2c
refine(platform): simplify permission lists and meeting idea cards
emir-karabeg Nov 6, 2026
72253b0
refine(platform): match calendar fill interaction timing
emir-karabeg Nov 6, 2026
1626e5c
refine(platform): unify modal fields and manual credentials
emir-karabeg Nov 6, 2026
cf841e5
fix(platform): preserve explicit back-link props
emir-karabeg Nov 6, 2026
5dad616
Merge platform-core-chat into the integration center
emir-karabeg Nov 7, 2026
bf9bfcd
fix(platform): mount the Settings leave guard on live data again
emir-karabeg Nov 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 3 additions & 3 deletions .agents/skills/implement-platform/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ Start in the Sim checkout containing the requested product work. Read the [Platf
1. **Establish scope on the real route.** Identify the product entry, interaction, phase, and affected consumers. When rebuilding an existing workflow, trace the old navigation target, its access gate, and the actions reachable by that viewer. Use that evidence to decide which controls belong on the new page before consulting the broader API or provider catalog. Phase 1 owns foundations and the library. Phase 2 owns working UI and transient interaction state, with examples supplied through the server fixture flag. Phase 3 connects real data and operations. Reuse the same renderer in the browser and Sim Desktop. Read the installed Next guides for the file structure or framework behavior you are changing.
For organization Settings, inventory the old sidebar in order, its viewer/deployment gates and every action reachable from each section. Map old header buttons to the row or section they act on. Verify the same destination and drilldown on the fixture and authenticated routes; keep real writes outside fixture sessions.
2. **Resolve design intent.** For Paper-backed work, use `$sim-paper-design` to locate the live Shared or Platform master and the product states that use it. Exclude Marcus. Preserve the key and theme roles. Treat artboard sizes as reference measurements. For code-first changes, follow the latest explicit product direction and inspect the rendered route. Identify any source you could not verify. Update the Paper canvas when the request includes Paper changes.
3. **Choose or change the owner.** Start with the behavior. An action, navigation row, value picker, or disclosure has an existing keyboard and pointer contract. Different interactions may share visual roles while retaining different semantics. Use the existing family and named props for a change in size, intent, icon, or content. Put unique anatomy and its CSS beside the route component. Keep page files free of styling. Only EMCN owns the appearance of its controls. Use Base UI there for complex keyboard, floating, and dismissal behavior.
4. **Trace the full change.** On a second independent feature use, promote the original implementation and migrate both callers. For consolidation, compare semantics, map every consumer to its replacement, then remove the obsolete implementation, export, variant styles, and unused registrations. For deletion, also check menus, preferences, fixture data, workbench references, and tests that existed only for the removed feature. Preserve unrelated consumers and historical Paper evidence. A new variant needs a reachable product use. Edit the source or compiler for generated foundations and recipes.
5. **Verify where people use it.** Run the design audit and applicable checks from the README. Render the changed product route with empty, full, stress, and fixture-off data as relevant. Check both themes, widths between artboards, long content, text scaling, keyboard, and pointer states. Compare shared controls in their actual consumers. Check the actual scroll edge and the open popup when space is tight. For shell, panel, or desktop work, exercise the real Electron renderer. For substantial implementations and consolidations, use an independent agent during design or implementation and for a final review of the changed owners and routes. Provide the working localhost route for visual review.
3. **Choose or change the owner.** Start with the behavior. An action, navigation row, value picker, or disclosure has an existing keyboard and pointer contract. Different interactions may share visual roles while retaining different semantics. Use the existing family and named props for a change in size, intent, icon, or content. Toolbar choices use ChoiceMenu, as Home's period does; Select/SelectField belong to forms and settings. Compare the rendered trigger, not just its variant name. Put unique anatomy and its CSS together in `_components/<component>/<component>.tsx` and `<component>.module.css`. Match an existing semantic rhythm, such as Home's ActivityRow, for a custom composition. Keep page files free of styling. Only EMCN owns the appearance of its controls. Use Base UI there for complex keyboard, floating, and dismissal behavior.
4. **Trace the full change.** On a second independent feature use, promote the original implementation and migrate both callers. For consolidation, compare semantics, map every consumer to its replacement, then remove the obsolete implementation, export, variant styles, and unused registrations. For deletion, also check menus, preferences, fixture data, workbench references, and tests that existed only for the removed feature. Preserve unrelated consumers and historical Paper evidence. Before adding a shared visual variant, name at least two independent real consumers. A single feature composes the existing primitives in its local owner; a label, icon, data value or responsive arrangement does not justify another variant. Keep the public API small enough to understand at the call site. Edit the source or compiler for generated foundations and recipes.
5. **Verify where people use it.** Run the design audit and applicable checks from the README. Render the changed product route with empty, full, stress, and fixture-off data as relevant. Check both themes, widths between artboards, long content, text scaling, keyboard, and pointer states. Compare shared controls in their actual consumers. Check the actual scroll edge and the open popup when space is tight. For shell, panel, or desktop work, exercise the real Electron renderer. For substantial implementations and consolidations, use an independent agent during design or implementation and for a final review of the changed owners and routes. Reuse the single review server at localhost:3125. Check its process working directory and branch before starting a server or moving work. Separate task worktrees do not update that preview until reconciled into its checkout. Provide the working route for visual review.
6. **Keep non-UI code in one place.** When work touches both the zone and `apps/sim/platform/embedded`, converge first rather than porting: only markup may differ. Follow "Converging a domain" in `apps/sim/platform/AGENTS.md`; `bun run check:platform-convergence` fails a new parallel file.
7. **Keep decisions durable.** Follow the contract’s maintenance guidance when an approved correction changes a shared rule. Record feature-specific decisions with their feature. For sustained work, keep a task checkpoint with the code revision, verified states, evidence, and outstanding work. Include the branch or PR, checkpoint path, and localhost route in a handoff. On resumption, compare the checkpoint with the current branch, working tree, and relevant live sources before acting.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import type { ReactNode } from 'react'
import { ChipLink, cn } from '@sim/emcn'
import { HEADER_ACTION_CLUSTER, PAGE_HEADER_BAR } from '@/components/page-header-bar'
import { workspaceIntegrationsPath } from '@/lib/navigation/paths'
import { useWorkspaceHostContext } from '@/app/workspace/[workspaceId]/providers/workspace-host-provider'

interface IntegrationTabsHeaderProps {
active: 'integrations' | 'skills'
Expand All @@ -17,9 +19,13 @@ export function IntegrationTabsHeader({
workspaceId,
rightSlot,
}: IntegrationTabsHeaderProps) {
const host = useWorkspaceHostContext()
return (
<div className={cn(PAGE_HEADER_BAR, 'gap-1')}>
<ChipLink href={`/workspace/${workspaceId}/integrations`} active={active === 'integrations'}>
<ChipLink
href={workspaceIntegrationsPath(workspaceId, host)}
active={active === 'integrations'}
>
Integrations
</ChipLink>
<ChipLink href={`/workspace/${workspaceId}/skills`} active={active === 'skills'}>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import type { ComponentType } from 'react'
import {
Database,
Download,
File,
FolderPlus,
Library,
Plus,
RefreshCw,
Table,
Upload,
} from '@sim/emcn/icons'
import { FOLDERED_RESOURCE_HEADERS } from '@/app/workspace/[workspaceId]/components/folders/foldered-resources'
import type { ChromeActionSpec } from '@/app/workspace/[workspaceId]/components/resource/components/resource-chrome-fallback'
import type { ResourceColumn } from '@/app/workspace/[workspaceId]/components/resource/resource'

interface ListChrome {
title: string
icon: ComponentType<{ className?: string }>
columns: readonly ResourceColumn[]
actions: readonly ChromeActionSpec[]
searchPlaceholder: string
hasSort: boolean
hasFilter: boolean
}

/** The original list chrome used for loading and for fixture rendering of a workspace page. */
export const RESOURCE_LIST_CHROME = {
tables: {
title: FOLDERED_RESOURCE_HEADERS.table.rootLabel,
icon: Table,
columns: [
{ id: 'name', header: 'Name' },
{ id: 'columns', header: 'Columns' },
{ id: 'rows', header: 'Rows' },
{ id: 'created', header: 'Created' },
{ id: 'owner', header: 'Owner' },
{ id: 'updated', header: 'Last Updated' },
],
actions: [
{ text: 'Import CSV', icon: Upload },
{ text: 'New folder', icon: FolderPlus },
{ text: 'New table', icon: Plus, variant: 'primary' },
],
searchPlaceholder: 'Search tables...',
hasSort: true,
hasFilter: true,
},
files: {
title: FOLDERED_RESOURCE_HEADERS.file.rootLabel,
icon: File,
columns: [
{ id: 'name', header: 'Name', widthMultiplier: 1.15 },
{ id: 'size', header: 'Size', widthMultiplier: 0.85 },
{ id: 'type', header: 'Type', widthMultiplier: 1.0 },
{ id: 'created', header: 'Created' },
{ id: 'owner', header: 'Owner' },
{ id: 'updated', header: 'Last Updated' },
],
actions: [
{ text: 'Upload', icon: Upload },
{ text: 'New folder', icon: FolderPlus },
{ text: 'New file', icon: Plus, variant: 'primary' },
],
searchPlaceholder: 'Search files...',
hasSort: true,
hasFilter: true,
},
knowledge: {
title: FOLDERED_RESOURCE_HEADERS.knowledge_base.rootLabel,
icon: Database,
columns: [
{ id: 'name', header: 'Name' },
{ id: 'documents', header: 'Documents', widthMultiplier: 0.6 },
{ id: 'tokens', header: 'Tokens', widthMultiplier: 0.6 },
{ id: 'connectors', header: 'Connectors', widthMultiplier: 0.7 },
{ id: 'created', header: 'Created' },
{ id: 'owner', header: 'Owner' },
{ id: 'updated', header: 'Last Updated' },
],
actions: [
{ text: 'New folder', icon: FolderPlus },
{ text: 'New base', icon: Plus, variant: 'primary' },
],
searchPlaceholder: 'Search knowledge bases...',
hasSort: true,
hasFilter: true,
},
logs: {
title: 'Logs',
icon: Library,
columns: [
{ id: 'workflow', header: 'Workflow' },
{ id: 'date', header: 'Date' },
{ id: 'status', header: 'Status' },
{ id: 'cost', header: 'Cost' },
{ id: 'trigger', header: 'Trigger' },
{ id: 'duration', header: 'Duration' },
],
actions: [
{ text: 'Export', icon: Download },
{ text: 'Refresh', icon: RefreshCw },
{ text: 'Logs', active: true },
{ text: 'Dashboard' },
],
searchPlaceholder: 'Search logs...',
hasSort: true,
hasFilter: true,
},
} as const satisfies Record<string, ListChrome>
34 changes: 3 additions & 31 deletions apps/sim/app/workspace/[workspaceId]/files/loading.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,8 @@
'use client'

import { File as FilesIcon, FolderPlus, Plus, Upload } from '@sim/emcn'
import {
type ChromeActionSpec,
ResourceChromeFallback,
} from '@/app/workspace/[workspaceId]/components/resource/components/resource-chrome-fallback'

const COLUMNS = [
{ id: 'name', header: 'Name', widthMultiplier: 1.15 },
{ id: 'size', header: 'Size', widthMultiplier: 0.85 },
{ id: 'type', header: 'Type', widthMultiplier: 1.0 },
{ id: 'created', header: 'Created' },
{ id: 'owner', header: 'Owner' },
{ id: 'updated', header: 'Last Updated' },
]

const ACTIONS: ChromeActionSpec[] = [
{ text: 'Upload', icon: Upload },
{ text: 'New folder', icon: FolderPlus },
{ text: 'New file', icon: Plus, variant: 'primary' },
]
import { ResourceChromeFallback } from '@/app/workspace/[workspaceId]/components/resource/components/resource-chrome-fallback'
import { RESOURCE_LIST_CHROME } from '@/app/workspace/[workspaceId]/components/resource/list-chrome'

export default function FilesLoading() {
return (
<ResourceChromeFallback
icon={FilesIcon}
title='Files'
columns={COLUMNS}
actions={ACTIONS}
searchPlaceholder='Search files...'
hasSort
hasFilter
/>
)
return <ResourceChromeFallback {...RESOURCE_LIST_CHROME.files} />
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
Search,
} from '@sim/emcn'
import { Lock } from '@sim/emcn/icons'
import { useParams } from 'next/navigation'
import { redirect, useParams } from 'next/navigation'
import { useQueryStates } from 'nuqs'
import {
blockTypeToIconMap,
Expand All @@ -22,6 +22,7 @@ import {
resolveCredentialDisplay,
} from '@/lib/integrations'
import { isIntegrationPermitted } from '@/lib/integrations/access'
import { workspaceIntegrationsPath } from '@/lib/navigation/paths'
import { IntegrationTabsHeader } from '@/app/workspace/[workspaceId]/components/integration-tabs-header'
import { IntegrationSection } from '@/app/workspace/[workspaceId]/integrations/components/integration-section'
import { IntegrationTile } from '@/app/workspace/[workspaceId]/integrations/components/integrations-showcase'
Expand All @@ -34,6 +35,7 @@ import {
integrationsParsers,
integrationsUrlKeys,
} from '@/app/workspace/[workspaceId]/integrations/search-params'
import { useWorkspaceHostContext } from '@/app/workspace/[workspaceId]/providers/workspace-host-provider'
import {
SettingsEmptyState,
SettingsQueryErrorState,
Expand Down Expand Up @@ -159,6 +161,10 @@ function ConnectedItem({ href, blockType, name, description, icon: Icon }: Conne
}

export function Integrations() {
const host = useWorkspaceHostContext()
const workspaceId = host.workspace.id
const destination = workspaceIntegrationsPath(workspaceId, host)
if (destination !== `/workspace/${workspaceId}/integrations`) redirect(destination)

@cubic-dev-ai cubic-dev-ai Bot Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This redirect drops the workspace page’s category and search query state, so filtered or bookmarked integration URLs open the organization list unfiltered. Translate the supported state (at least search to the organization route’s q) before redirecting.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At apps/sim/app/workspace/[workspaceId]/integrations/integrations.tsx, line 167:

<comment>This redirect drops the workspace page’s `category` and `search` query state, so filtered or bookmarked integration URLs open the organization list unfiltered. Translate the supported state (at least `search` to the organization route’s `q`) before redirecting.</comment>

<file context>
@@ -159,6 +161,10 @@ function ConnectedItem({ href, blockType, name, description, icon: Icon }: Conne
+  const host = useWorkspaceHostContext()
+  const workspaceId = host.workspace.id
+  const destination = workspaceIntegrationsPath(workspaceId, host)
+  if (destination !== `/workspace/${workspaceId}/integrations`) redirect(destination)
   return (
     <PermissionAccessBoundary configKey='hideIntegrationsTab'>
</file context>
Fix with cubic

Comment on lines +164 to +167

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Workspace credentials disappear from browsing

This redirects eligible members away from the workspace credential directory to a different list of member accounts. For example, the workspace page lists GitLab personal tokens, but the organization center treats GitLab as managed and supplies no accounts. Members lose the normal way to find and manage those credentials, and opening the old directory URL redirects them again.

Keep a workspace-credential entry reachable until the center supports these records and actions.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

return (
<PermissionAccessBoundary configKey='hideIntegrationsTab'>
<IntegrationsContent />
Expand Down
37 changes: 3 additions & 34 deletions apps/sim/app/workspace/[workspaceId]/knowledge/loading.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,8 @@
'use client'

import { Database, FolderPlus, Plus } from '@sim/emcn/icons'
import { FOLDERED_RESOURCE_HEADERS } from '@/app/workspace/[workspaceId]/components/folders/foldered-resources'
import {
type ChromeActionSpec,
ResourceChromeFallback,
} from '@/app/workspace/[workspaceId]/components/resource/components/resource-chrome-fallback'

const KNOWLEDGE_HEADER = FOLDERED_RESOURCE_HEADERS.knowledge_base

const COLUMNS = [
{ id: 'name', header: 'Name' },
{ id: 'documents', header: 'Documents', widthMultiplier: 0.6 },
{ id: 'tokens', header: 'Tokens', widthMultiplier: 0.6 },
{ id: 'connectors', header: 'Connectors', widthMultiplier: 0.7 },
{ id: 'created', header: 'Created' },
{ id: 'owner', header: 'Owner' },
{ id: 'updated', header: 'Last Updated' },
]

const ACTIONS: ChromeActionSpec[] = [
{ text: 'New folder', icon: FolderPlus },
{ text: 'New base', icon: Plus, variant: 'primary' },
]
import { ResourceChromeFallback } from '@/app/workspace/[workspaceId]/components/resource/components/resource-chrome-fallback'
import { RESOURCE_LIST_CHROME } from '@/app/workspace/[workspaceId]/components/resource/list-chrome'

export default function KnowledgeLoading() {
return (
<ResourceChromeFallback
icon={Database}
title={KNOWLEDGE_HEADER.rootLabel}
columns={COLUMNS}
actions={ACTIONS}
searchPlaceholder='Search knowledge bases...'
hasSort
hasFilter
/>
)
return <ResourceChromeFallback {...RESOURCE_LIST_CHROME.knowledge} />
}
36 changes: 3 additions & 33 deletions apps/sim/app/workspace/[workspaceId]/logs/loading.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,8 @@
'use client'

import { Library, RefreshCw } from '@sim/emcn'
import { Download } from '@sim/emcn/icons'
import {
type ChromeActionSpec,
ResourceChromeFallback,
} from '@/app/workspace/[workspaceId]/components/resource/components/resource-chrome-fallback'

const COLUMNS = [
{ id: 'workflow', header: 'Workflow' },
{ id: 'date', header: 'Date' },
{ id: 'status', header: 'Status' },
{ id: 'cost', header: 'Cost' },
{ id: 'trigger', header: 'Trigger' },
{ id: 'duration', header: 'Duration' },
]

const ACTIONS: ChromeActionSpec[] = [
{ text: 'Export', icon: Download },
{ text: 'Refresh', icon: RefreshCw },
{ text: 'Logs', active: true },
{ text: 'Dashboard' },
]
import { ResourceChromeFallback } from '@/app/workspace/[workspaceId]/components/resource/components/resource-chrome-fallback'
import { RESOURCE_LIST_CHROME } from '@/app/workspace/[workspaceId]/components/resource/list-chrome'

export default function LogsLoading() {
return (
<ResourceChromeFallback
icon={Library}
title='Logs'
columns={COLUMNS}
actions={ACTIONS}
searchPlaceholder='Search logs...'
hasSort
hasFilter
/>
)
return <ResourceChromeFallback {...RESOURCE_LIST_CHROME.logs} />
}
35 changes: 3 additions & 32 deletions apps/sim/app/workspace/[workspaceId]/tables/loading.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,8 @@
'use client'

import { Plus, Upload } from '@sim/emcn'
import { FolderPlus, Table as TableIcon } from '@sim/emcn/icons'
import {
type ChromeActionSpec,
ResourceChromeFallback,
} from '@/app/workspace/[workspaceId]/components/resource/components/resource-chrome-fallback'

const COLUMNS = [
{ id: 'name', header: 'Name' },
{ id: 'columns', header: 'Columns' },
{ id: 'rows', header: 'Rows' },
{ id: 'created', header: 'Created' },
{ id: 'owner', header: 'Owner' },
{ id: 'updated', header: 'Last Updated' },
]

const ACTIONS: ChromeActionSpec[] = [
{ text: 'Import CSV', icon: Upload },
{ text: 'New folder', icon: FolderPlus },
{ text: 'New table', icon: Plus, variant: 'primary' },
]
import { ResourceChromeFallback } from '@/app/workspace/[workspaceId]/components/resource/components/resource-chrome-fallback'
import { RESOURCE_LIST_CHROME } from '@/app/workspace/[workspaceId]/components/resource/list-chrome'

export default function TablesLoading() {
return (
<ResourceChromeFallback
icon={TableIcon}
title='Tables'
columns={COLUMNS}
actions={ACTIONS}
searchPlaceholder='Search tables...'
hasSort
hasFilter
/>
)
return <ResourceChromeFallback {...RESOURCE_LIST_CHROME.tables} />
}
Loading
Loading