Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
56246d8
feat(dashboards): add table-backed dashboard resources behind rollout…
TheodoreSpeaks Sep 25, 2026
90bbd59
refactor(files): separate discovery from storage context
TheodoreSpeaks Sep 25, 2026
a6e0941
fix(charts): keep pie labels readable and separate neutral colors
TheodoreSpeaks Sep 25, 2026
f894b9e
feat(dashboards): compute percentages from row conditions
TheodoreSpeaks Sep 25, 2026
743b0e3
refactor(dashboards): store dashboards as workspace files
TheodoreSpeaks Sep 26, 2026
0dc3b9d
Merge origin/staging into codex/research-sim-dashboards
TheodoreSpeaks Sep 26, 2026
26a9dd2
fix(dashboards): address review findings on chart layout and precision
TheodoreSpeaks Sep 26, 2026
6c58c01
fix(charts): size grouped bar rows and keep the row highlight through…
TheodoreSpeaks Sep 26, 2026
3d630db
Merge remote-tracking branch 'origin/staging' into codex/research-sim…
TheodoreSpeaks Sep 26, 2026
af21484
fix(charts): keep authored tooltip arrays and drop the v2 chat mode o…
TheodoreSpeaks Sep 26, 2026
bf3243c
fix(charts): reserve the authored bar gap between grouped bars
TheodoreSpeaks Sep 26, 2026
4f1b0e0
fix(charts): format index-encoded pie tooltips and test dashboard ref…
TheodoreSpeaks Sep 26, 2026
d736526
Merge remote-tracking branch 'origin/staging' into codex/research-sim…
TheodoreSpeaks Sep 26, 2026
8e34901
fix(charts): format bar tooltip values with each series' own value axis
TheodoreSpeaks Sep 26, 2026
bb59bdf
test(dashboards): drop mock-call and rendered-text assertions
TheodoreSpeaks Sep 26, 2026
dd4b207
Merge remote-tracking branch 'origin/staging' into codex/research-sim…
TheodoreSpeaks Sep 26, 2026
0958aab
test(dashboards): drop redundant mock resets and default environment …
TheodoreSpeaks Sep 26, 2026
a3e287e
refactor(dashboards): move authoring guidance to Mothership like Sim …
TheodoreSpeaks Sep 27, 2026
c2207cf
Merge remote-tracking branch 'origin/staging' into codex/research-sim…
TheodoreSpeaks Sep 27, 2026
54dfd1b
refactor(dashboards): give DashboardFeatureGate a props interface
TheodoreSpeaks Sep 27, 2026
4cc80af
feat(dashboards): report dashboard parse errors on file writes
TheodoreSpeaks Sep 27, 2026
5d0e7e4
fix(dashboards): split diagnostics, switch panel query modes, return …
TheodoreSpeaks Sep 27, 2026
68e8448
fix(dashboards): drop inherited ordering on query-mode switches and c…
TheodoreSpeaks Sep 27, 2026
470b450
feat(playground): org-level project view prototype
TheodoreSpeaks Sep 29, 2026
301c682
feat(playground): Supabase-style full view, settings in the sidebar, …
TheodoreSpeaks Sep 29, 2026
e4cd049
feat(playground): minimal black-and-white issues list, underline tabs…
TheodoreSpeaks Sep 30, 2026
6ab84c0
feat(playground): chat with the resource panel on the right; new tab …
TheodoreSpeaks Sep 30, 2026
11af0da
feat(playground): resource header is the full path, actions fold into…
TheodoreSpeaks Sep 30, 2026
8dc50fa
feat(resource): compact header keeps parent + current crumb so a narr…
TheodoreSpeaks Sep 30, 2026
ab81f6a
feat(resource): compact header is the current crumb alone, path on hover
TheodoreSpeaks Sep 30, 2026
912f0b2
feat(playground): + opens a New tab; browsing from it turns it into t…
TheodoreSpeaks Sep 30, 2026
2c9efe8
feat(playground): resource actions trail the tab strip; browser and t…
TheodoreSpeaks Sep 30, 2026
e342e50
feat(playground): chats are not scoped to projects
TheodoreSpeaks Sep 30, 2026
95dc82d
feat(playground): one project page with every section as a tab; full …
TheodoreSpeaks Sep 30, 2026
4e7607b
feat(playground): Resources tab lists every other kind under the proj…
TheodoreSpeaks Sep 30, 2026
092bde3
feat(playground): Chat about this opens a new chat with the thing in …
TheodoreSpeaks Sep 30, 2026
00a48d8
feat(playground): chat docks on the left of any project page from the…
TheodoreSpeaks Sep 30, 2026
ab38337
feat(playground): floating chat button starts a real chat with the pa…
TheodoreSpeaks Sep 30, 2026
eb297db
feat(playground): chat trigger is an icon at the top right of the pro…
TheodoreSpeaks Sep 30, 2026
828d23c
feat(playground): chats on the left, the workspace on the right
TheodoreSpeaks Sep 30, 2026
ffc8eef
feat(playground): home lists the projects under the composer; one cli…
TheodoreSpeaks Sep 30, 2026
f214bbf
feat(playground): Projects back in the sidebar; a project opens in th…
TheodoreSpeaks Oct 1, 2026
b225cbd
feat(playground): a project link goes Home with that project open; th…
TheodoreSpeaks Oct 1, 2026
6b4cf4a
feat(playground): home suggests what to do next under the composer
TheodoreSpeaks Oct 1, 2026
4d1df5d
feat(playground): a new tab starts on the pane's project; the browser…
TheodoreSpeaks Oct 1, 2026
5aa7077
feat(playground): Home and a second click on the active project desel…
TheodoreSpeaks Oct 1, 2026
edace95
feat(playground): Resources opens a browsing tab; bare workspace ref …
TheodoreSpeaks Oct 1, 2026
e8d3f69
feat(playground): browsing tab gets a search bar over the project's r…
TheodoreSpeaks Oct 1, 2026
9063f80
feat(playground): project rows in the browsing tab carry their tile
TheodoreSpeaks Oct 1, 2026
e0f0024
feat(playground): the search bar sits under the Browse section's label
TheodoreSpeaks Oct 1, 2026
f944167
feat(playground): Resources is the in-tab directory with real lists a…
TheodoreSpeaks Oct 1, 2026
e202859
feat(playground): the resource header bar stays on the Resources dire…
TheodoreSpeaks Oct 1, 2026
a09dc35
feat(playground): the project is a black profile chip at the head of …
TheodoreSpeaks Oct 1, 2026
e044127
feat(playground): quieter workspace tab
TheodoreSpeaks Oct 1, 2026
9280653
feat(playground): outlined project chip, title block back, no header …
TheodoreSpeaks Oct 1, 2026
cc58ff8
feat(playground): the dashboard is only the workspace tab's main view…
TheodoreSpeaks Oct 1, 2026
a614f67
feat(playground): the project tile in the strip is the switcher
TheodoreSpeaks Oct 1, 2026
7f8d6d5
feat(playground): the project switcher is one tile, filled edge to ed…
TheodoreSpeaks Oct 1, 2026
764c146
feat(playground): split profile control at the strip's right end
TheodoreSpeaks Oct 1, 2026
ef69716
feat(playground): resource actions sit in the resource's own header, …
TheodoreSpeaks Oct 1, 2026
4c016c0
feat(playground): expand toggle hides the chat; no divider on the pre…
TheodoreSpeaks Oct 1, 2026
685e1ce
feat(identity-tile): md size, the 24px toolbar mark
TheodoreSpeaks Oct 1, 2026
00383a1
feat(playground): new tab leads with Browse and search; Mentioned fol…
TheodoreSpeaks Oct 1, 2026
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
Prev Previous commit
Next Next commit
feat(playground): Resources is the in-tab directory with real lists a…
…nd create actions

Resources shows the kinds inside the workspace tab; a kind shows the real
list with its New/Upload/Connect action under a Resources / Kind breadcrumb
back to the directory; a row opens as its own resource tab.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014LcvZQzHFcm7Egc7rPEEHv
  • Loading branch information
TheodoreSpeaks and claude committed Oct 1, 2026
commit f9441676f24e751b35bbe9dcba5cbbe8e1e22cf4
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export function ChatResourcePanel({
onOpenTerminal,
onBrowse,
}: ChatResourcePanelProps) {
if (view.type === 'workspace') return <WorkspaceView onBrowse={onBrowse} />
if (view.type === 'workspace') return <WorkspaceView />
if (view.type === 'resource') return <ResourceBody resource={view.resource} />
if (view.type === 'browser') return <BrowserView />
if (view.type === 'terminal') return <TerminalView />
Expand Down
6 changes: 2 additions & 4 deletions apps/sim/app/playground/org/components/chat-surface.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ import {
WORKSPACES,
workspaceById,
} from '@/app/playground/org/lib/mock-data'
import type { ProjectSection } from '@/app/playground/org/lib/routes'
import { type ProjectSection, WORKSPACE_SECTIONS } from '@/app/playground/org/lib/routes'
import { protoParsers } from '@/app/playground/org/lib/search-params'
import { useWorkspacePane } from '@/app/playground/org/lib/workspace-pane-store'
import {
Expand Down Expand Up @@ -117,10 +117,8 @@ function tabFromRef(ref: string): PanelTab {
return newTab(workspaceId, kind)
}

const PROJECT_SECTIONS: readonly ProjectSection[] = ['dashboard', 'changelog', 'issues', 'settings']

function isProjectSection(value: string): value is ProjectSection {
return PROJECT_SECTIONS.includes(value as ProjectSection)
return value === 'resources' || WORKSPACE_SECTIONS.some((section) => section.id === value)
}

const NO_MESSAGES: ChatMessage[] = []
Expand Down
37 changes: 37 additions & 0 deletions apps/sim/app/playground/org/components/resource-kinds.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
'use client'

import { BrowseRow, BrowseSection } from '@/app/playground/org/components/browse-rows'
import { isPanelKind, resourcesOfKind } from '@/app/playground/org/lib/chat-resources'
import { RESOURCES, type Workspace } from '@/app/playground/org/lib/mock-data'
import { RESOURCE_SECTIONS, type WorkspaceSection } from '@/app/playground/org/lib/routes'
import { useWorkspacePane } from '@/app/playground/org/lib/workspace-pane-store'

function countOf(workspace: Workspace, id: WorkspaceSection): number | null {
if (id === 'credentials') return RESOURCES.credentials.length
return isPanelKind(id) ? resourcesOfKind(workspace, id).length : null
}

/** The Resources tab: every resource kind as a row, the way the new tab lists them. */
export function ResourceKinds({ workspace }: { workspace: Workspace }) {
const setSection = useWorkspacePane((state) => state.setSection)
return (
<div className='px-4 py-4'>
<BrowseSection label={`Browse ${workspace.name}`}>
{RESOURCE_SECTIONS.map((section) => {
const count = countOf(workspace, section.id)
return (
<BrowseRow key={section.id} onClick={() => setSection(section.id)}>
<section.icon className='size-[14px] shrink-0 text-[var(--text-icon)]' />
<span className='min-w-0 flex-1 truncate text-[var(--text-body)]'>
{section.label}
</span>
{count !== null && (
<span className='text-[var(--text-muted)] text-caption'>{count}</span>
)}
</BrowseRow>
)
})}
</BrowseSection>
</div>
)
}
116 changes: 116 additions & 0 deletions apps/sim/app/playground/org/components/resource-section.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
'use client'

import { useState } from 'react'
import { Chip, ChipTag } from '@sim/emcn'
import {
Database,
Files,
Folder,
Integration,
Library,
Plus,
Table,
Workflow,
} from '@sim/emcn/icons'
import { useQueryStates } from 'nuqs'
import { isPanelKind } from '@/app/playground/org/lib/chat-resources'
import { RESOURCES, type Workspace } from '@/app/playground/org/lib/mock-data'
import { protoParsers } from '@/app/playground/org/lib/search-params'
import { useWorkspacePane } from '@/app/playground/org/lib/workspace-pane-store'
import { timeCell } from '@/app/workspace/[workspaceId]/components/resource/components/time-cell'
import {
Resource,
type ResourceColumn,
type ResourceRow,
} from '@/app/workspace/[workspaceId]/components/resource/resource'

type ResourceSectionId = keyof typeof RESOURCES

const CONFIG: Record<
ResourceSectionId,
{
title: string
icon: React.ComponentType<{ className?: string }>
create?: string
meta: string
}
> = {
workflows: { title: 'Workflows', icon: Workflow, create: 'New workflow', meta: 'Status' },
logs: { title: 'Logs', icon: Library, meta: 'Result' },
tables: { title: 'Tables', icon: Table, create: 'New table', meta: 'Rows' },
files: { title: 'Files', icon: Files, create: 'Upload', meta: 'Type' },
knowledge: { title: 'Knowledge', icon: Database, create: 'New base', meta: 'Documents' },
credentials: { title: 'Integrations', icon: Integration, create: 'Connect', meta: 'Status' },
}

const COLUMNS: ResourceColumn[] = [
{ id: 'name', header: 'Name', widthMultiplier: 2 },
{ id: 'meta', header: 'Detail' },
{ id: 'owner', header: 'Owner' },
{ id: 'updated', header: 'Updated' },
]

interface ResourceSectionProps {
workspace: Workspace
section: ResourceSectionId
}

/** The existing Resource list over static rows, under a breadcrumb back to the directory; a row opens as a tab. */
export function ResourceSection({ workspace, section }: ResourceSectionProps) {
const [, setParams] = useQueryStates(protoParsers)
const setSection = useWorkspacePane((state) => state.setSection)
const config = CONFIG[section]
const [search, setSearch] = useState('')
const Icon = config.icon
const rows: ResourceRow[] = RESOURCES[section]
.filter((item) => item.name.toLowerCase().includes(search.toLowerCase()))
.map((item) => ({
id: item.id,
cells: {
name: { icon: <Icon className='size-[14px] text-[var(--text-icon)]' />, label: item.name },
meta: /expired|error|failing/i.test(item.meta)
? { content: <ChipTag variant='gray'>{item.meta}</ChipTag> }
: { label: item.meta },
owner: { label: item.owner },
updated: timeCell(item.updated),
},
}))
return (
<Resource>
<Resource.Header
icon={Folder}
breadcrumbs={[
{ label: 'Resources', onClick: () => setSection('resources') },
{ label: config.title, icon: Icon },
]}
/>
<Resource.Options
trailing={
config.create ? (
<Chip variant='primary' leftIcon={Plus}>
{config.create}
</Chip>
) : undefined
}
search={{
value: search,
onChange: setSearch,
placeholder: `Search ${config.title.toLowerCase()}`,
}}
/>
<Resource.Table
columns={COLUMNS}
rows={rows}
onRowClick={
isPanelKind(section)
? (id) => {
const item = RESOURCES[section].find((candidate) => candidate.id === id)
if (!item) throw new Error(`Unknown ${section} row ${id}`)
void setParams({ open: `${section}:${workspace.id}:${id}` })
}
: undefined
}
/>
</Resource>
)
}
45 changes: 24 additions & 21 deletions apps/sim/app/playground/org/components/workspace-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,38 +10,45 @@ import {
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@sim/emcn'
import { ArrowUpRight, Check, ChevronDown, Settings } from '@sim/emcn/icons'
import { Check, ChevronDown, Settings } from '@sim/emcn/icons'
import { IdentityTile } from '@/components/identity-tile/identity-tile'
import { BrowseRow, BrowseSection } from '@/app/playground/org/components/browse-rows'
import { Changelog } from '@/app/playground/org/components/changelog'
import { IssuesList } from '@/app/playground/org/components/issues-list'
import { ProjectSettings } from '@/app/playground/org/components/project-settings'
import { ProtoDashboard } from '@/app/playground/org/components/proto-dashboard'
import type { PanelKind } from '@/app/playground/org/lib/chat-resources'
import { ResourceKinds } from '@/app/playground/org/components/resource-kinds'
import { ResourceSection } from '@/app/playground/org/components/resource-section'
import { ORGANIZATION, WORKSPACES, workspaceById } from '@/app/playground/org/lib/mock-data'
import { MAIN_SECTIONS, type ProjectSection } from '@/app/playground/org/lib/routes'
import {
MAIN_SECTION_IDS,
MAIN_SECTIONS,
type ProjectSection,
} from '@/app/playground/org/lib/routes'
import { SETTINGS_NAV } from '@/app/playground/org/lib/settings-nav'
import { useWorkspacePane } from '@/app/playground/org/lib/workspace-pane-store'

const TABS = MAIN_SECTIONS.map((item) => ({ id: item.id as ProjectSection, label: item.label }))
const TABS = [
...MAIN_SECTIONS.map((item) => ({ id: item.id as ProjectSection, label: item.label })),
{ id: 'resources' as ProjectSection, label: 'Resources' },
]

const TAB_CLASS = '-mb-px border-b-2 pb-2.5 text-small transition-colors'
const TAB_IDLE_CLASS =
'border-transparent text-[var(--text-muted)] hover-hover:text-[var(--text-body)]'

interface WorkspaceViewProps {
/** Resources opens the project's kinds in a browsing tab of its own. */
onBrowse: (workspaceId: string, kind: PanelKind | null) => void
}

/**
* The workspace tab: pick a project, then its dashboard, changelog, and issues. Resources
* leaves the tab: it opens the project's kinds in a new tab, the way the + button does.
* The workspace tab: pick a project, then its dashboard, changelog, issues, and resources.
* Resources is the directory: every other kind with its real list and create actions; a row
* opens as a resource tab of its own.
*/
export function WorkspaceView({ onBrowse }: WorkspaceViewProps) {
export function WorkspaceView() {
const { projectId, section, setProject, setSection } = useWorkspacePane()
if (!projectId) return <ProjectPicker onPick={setProject} />
const workspace = workspaceById(projectId)
const activeTab: ProjectSection = MAIN_SECTION_IDS.includes(section as never)
? section
: 'resources'
return (
<div className='flex h-full min-h-0 flex-col'>
<header className='flex shrink-0 flex-col gap-3 px-6 pt-5'>
Expand Down Expand Up @@ -79,7 +86,7 @@ export function WorkspaceView({ onBrowse }: WorkspaceViewProps) {
className='flex items-center gap-6 border-[var(--border)] border-b'
>
{TABS.map((item) => {
const active = section === item.id
const active = activeTab === item.id
return (
<button
key={item.id}
Expand All @@ -97,14 +104,6 @@ export function WorkspaceView({ onBrowse }: WorkspaceViewProps) {
</button>
)
})}
<button
type='button'
onClick={() => onBrowse(workspace.id, null)}
className={cn(TAB_CLASS, TAB_IDLE_CLASS, 'flex items-center gap-1')}
>
Resources
<ArrowUpRight className='size-[12px]' />
</button>
</nav>
</header>
<div className='min-h-0 flex-1 overflow-y-auto'>
Expand Down Expand Up @@ -154,6 +153,8 @@ function SectionBody({ section }: { section: ProjectSection }) {
return <Changelog workspace={workspace} />
case 'issues':
return <IssuesList workspace={workspace} />
case 'resources':
return <ResourceKinds workspace={workspace} />
case 'settings':
return (
<div className='flex flex-col gap-2'>
Expand All @@ -167,5 +168,7 @@ function SectionBody({ section }: { section: ProjectSection }) {
<ProjectSettings workspace={workspace} sectionId={settingsSection} />
</div>
)
default:
return <ResourceSection workspace={workspace} section={section} />
}
}
7 changes: 4 additions & 3 deletions apps/sim/app/playground/org/lib/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,13 @@ export const WORKSPACE_SECTIONS = [

export type WorkspaceSection = (typeof WORKSPACE_SECTIONS)[number]['id']

/** Tabs of the workspace pane; every other kind opens in a browsing tab from Resources. */
/** Tabs of the workspace pane; every other section lives under Resources. */
export const MAIN_SECTION_IDS: readonly WorkspaceSection[] = ['dashboard', 'changelog', 'issues']
export const MAIN_SECTIONS = WORKSPACE_SECTIONS.filter((s) => MAIN_SECTION_IDS.includes(s.id))
export const RESOURCE_SECTIONS = WORKSPACE_SECTIONS.filter((s) => !MAIN_SECTION_IDS.includes(s.id))

/** What the workspace tab shows: one of its tabs, or settings from the project menu. */
export type ProjectSection = 'dashboard' | 'changelog' | 'issues' | 'settings'
/** What the workspace tab shows: a section, or the Resources directory listing the rest. */
export type ProjectSection = WorkspaceSection | 'resources'

/**
* Everything lives beside a chat, so a link to a project thing is a `?open=` ref the chat
Expand Down