Skip to content

Commit 904bac7

Browse files
committed
refactor(knowledge): make the shell the canonical view
The panel now mounts `KnowledgeView` and imports nothing from the workspace route tree. That was the last of the four kinds. The shape of this one differs from tables, and the difference is the useful part: the route shell owned the *whole* surface — header, breadcrumbs, ten modals, bulk operations, the context menu — while the extracted `KnowledgeView` was only the document list. So the shell became the view, and the previous view became its `DocumentList` child. Promoting the read-only half and leaving the mutations behind would have left the panel importing the route tree forever. Dropped `id` from the props: `source` already carries it (`knowledgeResourceId`), and two spellings of the same identity is exactly what the axes replace. `knowledgeBaseName` stays, documented as a title hint rather than identity — it is what keeps both hosts from flashing a placeholder header before load. Four boundary violations surfaced by `check:resources` once the files were inside a unit, each fixed at the cause rather than annotated: - `AddDocumentsModal` read `useParams()` for the workspace id. Inside the panel there is no `[workspaceId]` segment, so this was already returning undefined there — the modal is reachable from `/home`. Now a required prop. - `use-connector-config-fields` was route-tree-resident but is unit-internal; moved to `@/hooks/kb/`. - `BreadcrumbItem`/`ResourceAction` came from the route barrel that merely re-exports `@/components/resource`. Retargeted to the source. - The knowledge list page and the document route imported past the unit barrel. They render the same tag editor and selection bar against the same data, so the barrel exports those three children — and the rule now says when that is allowed, because "saves an import hop" must not qualify. `ConnectOAuthModal` and `WorkspaceHostProvider` looked like they pinned the connector modals to the route tree. Neither is route-specific: both moved to `components/` (with `WorkspaceAccessDenied`, which the provider renders), 22 importers repointed. Deleting the blocker beat splitting the surface around it. nuqs stays outside the unit — R6 has no escape hatch — so `use-knowledge-list-state` moved to `@/hooks/kb/` and its parsers to `@/lib/knowledge/detail-search-params`, mirroring the table. Suite: 20917 passed, unchanged from before the move. R6 and R3c both 0.
1 parent c2f04e9 commit 904bac7

69 files changed

Lines changed: 1497 additions & 1440 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.claude/rules/sim-resource-views.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,21 @@ Every unit has the same layout, so moving between them costs nothing:
4141

4242
```
4343
<unit>/
44-
├── <unit>.tsx # THE view — the only component the barrel mounts
44+
├── <unit>.tsx # THE view — what consumers mount
4545
├── index.ts # the barrel; the only entry point consumers use
4646
├── components/<child>/ # <child>.tsx + index.ts, one folder per child
4747
├── hooks/<name>.ts # optional; tests colocated
4848
├── utils/<name>.ts # pure helpers; tests colocated
4949
└── types.ts # optional; shared types the whole unit reads
5050
```
5151

52+
A barrel may also export a **child** — but only one a surface outside the unit
53+
genuinely renders against the same data, where forking it would be the drift the
54+
unit exists to prevent (`knowledge-view` exports `ActionBar`, `BaseTagsModal` and
55+
`DocumentTagsModal` for the knowledge list page and the document detail route).
56+
Exporting a child to save an import hop is not that; the child stays private and
57+
the consumer mounts the view.
58+
5259
Imports **inside** a unit are absolute (`@/components/resources/<unit>/...`) like
5360
everywhere else in the app. The one exception is a folder's own `index.ts`
5461
naming its siblings, which stays relative (`./<child>`) — it is describing its

apps/sim/app/workspace/[workspaceId]/components/invite-modal/invite-modal.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ vi.mock('@/lib/auth/auth-client', () => ({
3535
useSession: () => ({ data: { user: { id: 'user-1', email: 'viewer@example.com' } } }),
3636
}))
3737

38-
vi.mock('@/app/workspace/[workspaceId]/providers/workspace-host-provider', () => ({
38+
vi.mock('@/components/workspace-host-provider', () => ({
3939
useWorkspaceHostContext: () => hostContext.current,
4040
}))
4141

apps/sim/app/workspace/[workspaceId]/components/invite-modal/invite-modal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ import {
1313
toast,
1414
} from '@sim/emcn'
1515
import { createLogger } from '@sim/logger'
16+
import { useWorkspaceHostContext } from '@/components/workspace-host-provider'
1617
import type { BatchInvitationResult } from '@/lib/api/contracts/invitations'
1718
import { useSession } from '@/lib/auth/auth-client'
1819
import { isEnterprise } from '@/lib/billing/plan-helpers'
1920
import { isBillingEnabled } from '@/lib/core/config/env-flags'
2021
import { quickValidateEmail } from '@/lib/messaging/email/validation'
2122
import type { PermissionType } from '@/lib/workspaces/permissions/utils'
22-
import { useWorkspaceHostContext } from '@/app/workspace/[workspaceId]/providers/workspace-host-provider'
2323
import { useSendWorkspaceInvitations } from '@/hooks/queries/invitations'
2424
import { useOrganizationBilling } from '@/hooks/queries/organization'
2525
import { useAdminWorkspaces } from '@/hooks/queries/workspace'

apps/sim/app/workspace/[workspaceId]/home/components/credits-chip/credits-chip.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ vi.mock('@/lib/auth/auth-client', () => ({
5656
useSession: () => ({ data: mockSession.current }),
5757
}))
5858

59-
vi.mock('@/app/workspace/[workspaceId]/providers/workspace-host-provider', () => ({
59+
vi.mock('@/components/workspace-host-provider', () => ({
6060
useWorkspaceHostContext: () => mockHostContext.current,
6161
}))
6262

apps/sim/app/workspace/[workspaceId]/home/components/credits-chip/credits-chip.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import { Chip, ChipTag, Tooltip } from '@sim/emcn'
55
import { Credit } from '@sim/emcn/icons'
66
import { useQueryClient } from '@tanstack/react-query'
77
import { useParams, useRouter } from 'next/navigation'
8+
import { useWorkspaceHostContext } from '@/components/workspace-host-provider'
89
import { useSession } from '@/lib/auth/auth-client'
910
import { formatCredits } from '@/lib/billing/credits/conversion'
1011
import { buildUpgradeHref } from '@/lib/billing/upgrade-reasons'
1112
import { canManageWorkspaceBilling } from '@/lib/billing/workspace-permissions'
1213
import { isBillingEnabled } from '@/lib/core/config/env-flags'
13-
import { useWorkspaceHostContext } from '@/app/workspace/[workspaceId]/providers/workspace-host-provider'
1414
import { prefetchWorkspaceSettings } from '@/hooks/queries/workspace'
1515
import { useWorkspaceCreditAvailability } from '@/hooks/queries/workspace-usage'
1616

apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/special-tags.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
type WorkspaceResourceTagType,
3232
} from '@/components/chat/special-tags/parse'
3333
import { ThinkingLoader } from '@/components/ui'
34+
import { useWorkspaceHostContext } from '@/components/workspace-host-provider'
3435
import { useSession } from '@/lib/auth/auth-client'
3536
import { buildHostedUpgradeUrl, HOSTED_BILLING_SETTINGS_URL } from '@/lib/billing/upgrade-reasons'
3637
import { canManageWorkspaceBilling } from '@/lib/billing/workspace-permissions'
@@ -65,7 +66,6 @@ import type {
6566
// ConnectServiceAccountModal, and that edge would pull the modal into this
6667
// chunk and defeat the lazy() split below.
6768
import { useServiceAccountConnectTarget } from '@/app/workspace/[workspaceId]/integrations/components/connect-service-account-modal/use-service-account-connect'
68-
import { useWorkspaceHostContext } from '@/app/workspace/[workspaceId]/providers/workspace-host-provider'
6969
import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider'
7070
import { useWorkspaceCredential } from '@/hooks/queries/credentials'
7171
import {

apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/resource-content.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@ import {
2525
import { createLogger } from '@sim/logger'
2626
import { useRouter } from 'next/navigation'
2727
import { FileView, type PreviewMode, resolveFileCategory } from '@/components/resources/file-view'
28+
import { KnowledgeView } from '@/components/resources/knowledge-view'
2829
import { LogView } from '@/components/resources/log-view'
2930
import { ResourceEmptyState } from '@/components/resources/resource-empty-state'
3031
import { TableView } from '@/components/resources/table-view'
32+
import { useWorkspaceHostContext } from '@/components/workspace-host-provider'
3133
import { isApiClientError } from '@/lib/api/client/errors'
3234
import { useSession } from '@/lib/auth/auth-client'
3335
import { getWorkspaceUsageLimitAction } from '@/lib/billing/workspace-permissions'
@@ -54,8 +56,6 @@ import type {
5456
MothershipResource,
5557
MothershipResourceType,
5658
} from '@/app/workspace/[workspaceId]/home/types'
57-
import { KnowledgeBase } from '@/app/workspace/[workspaceId]/knowledge/[id]/knowledge-base'
58-
import { useWorkspaceHostContext } from '@/app/workspace/[workspaceId]/providers/workspace-host-provider'
5959
import {
6060
useUserPermissionsContext,
6161
useWorkspacePermissionsContext,
@@ -381,9 +381,8 @@ export const ResourceContent = memo(function ResourceContent({
381381

382382
case 'knowledgebase':
383383
return (
384-
<KnowledgeBase
384+
<KnowledgeView
385385
key={resource.id}
386-
id={resource.id}
387386
knowledgeBaseName={resource.title}
388387
source={knowledgeSource}
389388
grants={grants}

apps/sim/app/workspace/[workspaceId]/home/components/suggested-actions/suggested-actions.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { stripVersionSuffix } from '@sim/utils/string'
88
import { useParams } from 'next/navigation'
99
import { usePostHog } from 'posthog-js/react'
1010
import { ActionRow } from '@/components/action-row'
11+
import { ConnectOAuthModal } from '@/components/connect-oauth-modal'
1112
import { GmailIcon, SlackIcon } from '@/components/icons'
1213
import {
1314
INTEGRATIONS,
@@ -16,7 +17,6 @@ import {
1617
resolveOAuthServiceForSlug,
1718
} from '@/lib/integrations'
1819
import { captureEvent } from '@/lib/posthog/client'
19-
import { ConnectOAuthModal } from '@/app/workspace/[workspaceId]/components/connect-oauth-modal'
2020
import { getBareIconStyle } from '@/blocks/brand-icon-style'
2121
import { getAllBlockMeta } from '@/blocks/registry'
2222
import type { ModuleTag } from '@/blocks/types'

apps/sim/app/workspace/[workspaceId]/integrations/[block]/integration-block-detail.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { Chip, ChipDropdown, ChipLink, cn } from '@sim/emcn'
55
import { ArrowLeft, Plus } from '@sim/emcn/icons'
66
import { useRouter } from 'next/navigation'
77
import { useQueryState } from 'nuqs'
8+
import { ConnectOAuthModal } from '@/components/connect-oauth-modal'
89
import { HEADER_ACTION_CLUSTER, PAGE_HEADER_BAR } from '@/components/page-header-bar'
910
import { isChatEnabled } from '@/lib/core/config/env-flags'
1011
import {
@@ -14,7 +15,6 @@ import {
1415
resolveOAuthServiceForIntegration,
1516
} from '@/lib/integrations'
1617
import { credentialProviderMatchesService } from '@/lib/oauth'
17-
import { ConnectOAuthModal } from '@/app/workspace/[workspaceId]/components/connect-oauth-modal'
1818
import { RESOURCE_TILE_BASE } from '@/app/workspace/[workspaceId]/components/resource-tile'
1919
import { IntegrationSkillsSection } from '@/app/workspace/[workspaceId]/integrations/[block]/integration-skills-section'
2020
import { connectParam } from '@/app/workspace/[workspaceId]/integrations/[block]/search-params'
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
export { ChunkContextMenu } from './chunk-context-menu'
22
export { ChunkEditor } from './chunk-editor'
33
export { DeleteChunkModal } from './delete-chunk-modal'
4-
export { DocumentTagsModal } from './document-tags-modal'

0 commit comments

Comments
 (0)