Skip to content

Commit f16bd16

Browse files
committed
improvement(org): settle the redesign's cleanup and simplify findings
1 parent b3c0c77 commit f16bd16

28 files changed

Lines changed: 111 additions & 256 deletions

File tree

‎.github/scripts/http-e2e.sh‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,8 +280,8 @@ case "$group" in
280280
esac
281281
;;
282282

283-
# One hosted Enterprise organization shaped like a real customer, a scripted worker in place of the
284-
# model, and the app twice: as that customer has it, then with People on. Hosted is decided by the
283+
# One hosted Enterprise organization, a scripted worker in place of the
284+
# model, and the app twice: with People off, then on. Hosted is decided by the
285285
# app's hostname, which the job maps to loopback. Both phases report, whichever fails.
286286
org-redesign)
287287
app_server=start
Lines changed: 3 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
/**
22
* @vitest-environment jsdom
33
*
4-
* A surface's own landing must not change the conversation it fronts. Failure modes: Home's
5-
* Assistant sharing Search's unsent question, a new chat losing its Search address, the landing
6-
* outliving the first turn, a restored chat entry flashing the dashboard's skeleton, and a caller
7-
* without a landing (the extension, Search) seeing any of it.
4+
* Transient states a browser run cannot hold still. Failure modes: the landing rendering before the
5+
* session arrives, and a restored chat entry flashing the dashboard while the router takes over.
86
*/
97
import { act, type ReactNode } from 'react'
108
import { authClientMock, authClientMockFns } from '@sim/testing/mocks/auth-client.mock'
@@ -24,12 +22,10 @@ import {
2422
import { NuqsTestingAdapter } from 'nuqs/adapters/testing'
2523
import { createRoot, type Root } from 'react-dom/client'
2624
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
27-
import { useMothershipDraftsStore } from '@/stores/mothership-drafts/store'
2825

2926
const mocks = vi.hoisted(() => ({
3027
chat: vi.fn(),
3128
composer: vi.fn(),
32-
send: vi.fn(),
3329
}))
3430
vi.mock('@/app/workspace/[workspaceId]/providers/feature-flags-provider', () => ({
3531
useFeatureFlag: () => false,
@@ -78,9 +74,6 @@ import {
7874
type OrganizationLandingSlot,
7975
} from '@/app/o/[organizationId]/components/organization-conversation'
8076

81-
const SEARCH_DRAFT = 'reader:organization:organization-a:search-assistant'
82-
const HOME_DRAFT = 'reader:organization:organization-a:home-assistant'
83-
8477
const landing = {
8578
fallback: <div>Dashboard skeleton</div>,
8679
render: ({ requestMode, composer, shortcuts }: OrganizationLandingSlot) => (
@@ -101,17 +94,10 @@ async function render(element: ReactNode) {
10194
})
10295
}
10396

104-
function composerProps() {
105-
const call = mocks.composer.mock.lastCall
106-
if (!call) throw new Error('Composer has not rendered')
107-
return call[0]
108-
}
109-
11097
beforeEach(() => {
11198
vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true)
11299
reactQueryMockFns.mockUseQuery.mockReturnValue(createQueryResultMock())
113100
reactQueryMockFns.mockUseMutation.mockReturnValue(createMutationResultMock())
114-
useMothershipDraftsStore.setState({ drafts: {} })
115101
nextNavigationMockFns.mockUsePathname.mockReturnValue('/o/organization-a/home')
116102
authClientMockFns.mockUseSession.mockReturnValue({ data: { user: { id: 'reader' } } })
117103
organizationProviderMockFns.mockUseOrganizationContext.mockReturnValue({
@@ -121,7 +107,7 @@ beforeEach(() => {
121107
canBuild: false,
122108
viewer: { isAdmin: false, canUseSearchMcp: true },
123109
})
124-
mocks.chat.mockReturnValue({ messages: [], resources: [], sendMessage: mocks.send })
110+
mocks.chat.mockReturnValue({ messages: [], resources: [], sendMessage: vi.fn() })
125111
mocks.composer.mockReturnValue(<div>Question composer</div>)
126112
container = document.createElement('div')
127113
document.body.appendChild(container)
@@ -134,69 +120,6 @@ afterEach(async () => {
134120
})
135121

136122
describe('an Assistant conversation on a surface with its own landing', () => {
137-
it('hands its composer and the Assistant shortcuts to the surface’s landing, in place of the default heading', async () => {
138-
await render(
139-
<OrganizationConversation
140-
requestMode='assistant'
141-
draftId='home-assistant'
142-
landing={landing}
143-
/>
144-
)
145-
expect(container.textContent).toContain('Dashboard for assistant')
146-
expect(container.textContent).toContain('Question composer')
147-
expect(container.querySelector('[data-testid="shortcuts"]')?.textContent).toBe(
148-
'Legacy get started'
149-
)
150-
expect(container.querySelector('h1')).toBeNull()
151-
})
152-
153-
it('keeps its unsent question apart from Search’s Assistant, in both directions', async () => {
154-
useMothershipDraftsStore.getState().setDraft(SEARCH_DRAFT, { text: 'Asked from Search' })
155-
await render(
156-
<OrganizationConversation
157-
requestMode='assistant'
158-
draftId='home-assistant'
159-
landing={landing}
160-
/>
161-
)
162-
expect(composerProps().value).toBe('')
163-
await act(async () => composerProps().onChange('Asked from Home'))
164-
const { drafts } = useMothershipDraftsStore.getState()
165-
expect(drafts[HOME_DRAFT]?.text).toBe('Asked from Home')
166-
expect(drafts[SEARCH_DRAFT]?.text).toBe('Asked from Search')
167-
})
168-
169-
it('addresses a new chat under Search, in the Assistant view', async () => {
170-
await render(
171-
<OrganizationConversation
172-
requestMode='assistant'
173-
draftId='home-assistant'
174-
landing={landing}
175-
/>
176-
)
177-
const [, chatId, options] = mocks.chat.mock.lastCall ?? []
178-
expect(chatId).toBeUndefined()
179-
expect(options.requestMode).toBe('assistant')
180-
expect(options.getChatUrl('chat-1')).toBe('/o/organization-a/search/chat/chat-1?mode=assistant')
181-
})
182-
183-
it('gives way to today’s conversation view at the first turn', async () => {
184-
mocks.chat.mockReturnValue({
185-
messages: [{ id: 'turn' }],
186-
resources: [],
187-
sendMessage: mocks.send,
188-
})
189-
await render(
190-
<OrganizationConversation
191-
requestMode='assistant'
192-
draftId='home-assistant'
193-
landing={landing}
194-
/>
195-
)
196-
expect(container.textContent).toContain('Conversation view')
197-
expect(container.textContent).not.toContain('Dashboard for')
198-
})
199-
200123
it('holds the surface’s fallback until the session arrives', async () => {
201124
authClientMockFns.mockUseSession.mockReturnValue({ data: null })
202125
await render(<OrganizationConversation requestMode='assistant' landing={landing} />)
@@ -209,13 +132,3 @@ describe('an Assistant conversation on a surface with its own landing', () => {
209132
expect(container.textContent).toBe('')
210133
})
211134
})
212-
213-
describe('a conversation without a landing', () => {
214-
it('keeps today’s landing and Search’s draft key', async () => {
215-
useMothershipDraftsStore.getState().setDraft(SEARCH_DRAFT, { text: 'Asked from Search' })
216-
await render(<OrganizationConversation requestMode='assistant' />)
217-
expect(container.querySelector('h1')?.textContent).toBe('Search Acme')
218-
expect(container.textContent).toContain('Legacy get started')
219-
expect(composerProps().value).toBe('Asked from Search')
220-
})
221-
})

‎apps/sim/app/o/[organizationId]/components/organization-page/search-params.ts‎

Lines changed: 0 additions & 22 deletions
This file was deleted.

‎apps/sim/app/o/[organizationId]/components/organization-page/use-organization-page-filters.ts‎

Lines changed: 0 additions & 21 deletions
This file was deleted.

‎apps/sim/app/o/[organizationId]/home/page.test.tsx‎

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,6 @@ vi.mock('@/platform/app/(shell)/home/_components/home-dashboard/home-dashboard-s
2222
<div>Home for {requestMode}</div>
2323
),
2424
}))
25-
vi.mock('@/app/o/[organizationId]/integrations/integrations', () => ({
26-
OrganizationIntegrations: () => <div>Integrations</div>,
27-
}))
2825
vi.mock('@/platform/app/(shell)/search/_components/search-surface/search-surface', () => ({
2926
OrganizationSearchSurface: () => <div>Standalone Search</div>,
3027
}))
Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,28 @@
1-
import { type ComponentProps, Suspense } from 'react'
1+
import { Suspense } from 'react'
22
import type { SessionPrincipal } from '@sim/auth/principal'
33
import type { OrganizationSurfaceContext } from '@/lib/organizations/surface'
44
import { Hydrated } from '@/app/o/[organizationId]/_redesign/hydrated'
5-
import { OrganizationIntegrations } from '@/app/o/[organizationId]/integrations/integrations'
65
import { IntegrationsHost } from '@/app/o/[organizationId]/integrations/integrations-host'
7-
import { IntegrationsRouteFallback } from '@/platform/app/(shell)/integrations/_components/integrations-page/integrations-route'
6+
import {
7+
IntegrationsRoute,
8+
IntegrationsRouteFallback,
9+
type IntegrationsRouteProps,
10+
} from '@/platform/app/(shell)/integrations/_components/integrations-page/integrations-route'
811
import { prefetchIntegrations } from '@/platform/lib/data/prefetch-member-inventory'
912

10-
interface HydratedIntegrationsProps extends ComponentProps<typeof OrganizationIntegrations> {
13+
interface HydratedIntegrationsProps extends Omit<IntegrationsRouteProps, 'organizationId'> {
1114
surface: OrganizationSurfaceContext
1215
principal: SessionPrincipal
1316
}
1417

1518
export function HydratedIntegrations({ surface, principal, ...route }: HydratedIntegrationsProps) {
1619
return (
17-
<Suspense
18-
fallback={
19-
<IntegrationsHost>
20-
<IntegrationsRouteFallback detail={Boolean(route.section)} />
21-
</IntegrationsHost>
22-
}
23-
>
24-
<Hydrated state={prefetchIntegrations(surface, principal)}>
25-
<OrganizationIntegrations {...route} />
26-
</Hydrated>
27-
</Suspense>
20+
<IntegrationsHost>
21+
<Suspense fallback={<IntegrationsRouteFallback detail={Boolean(route.section)} />}>
22+
<Hydrated state={prefetchIntegrations(surface, principal)}>
23+
<IntegrationsRoute organizationId={surface.organization.id} {...route} />
24+
</Hydrated>
25+
</Suspense>
26+
</IntegrationsHost>
2827
)
2928
}

‎apps/sim/app/o/[organizationId]/integrations/integrations.tsx‎

Lines changed: 0 additions & 17 deletions
This file was deleted.

‎apps/sim/app/o/[organizationId]/integrations/search-params.ts‎

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
import { createLoader, createSerializer, parseAsString } from 'nuqs/server'
2-
import { organizationPageParsers } from '@/app/o/[organizationId]/components/organization-page/search-params'
2+
3+
/** The list's search text, written raw and debounced on the way to the URL. */
4+
export const integrationSearchParsers = {
5+
q: parseAsString.withDefault(''),
6+
} as const
7+
8+
export const integrationSearchUrlKeys = {
9+
history: 'replace',
10+
clearOnDefault: true,
11+
} as const
312

413
export const integrationViewParsers = {
514
integration: parseAsString,
@@ -8,13 +17,13 @@ export const integrationViewParsers = {
817
} as const
918

1019
export const serializeIntegrationView = createSerializer({
11-
...organizationPageParsers,
20+
...integrationSearchParsers,
1221
...integrationViewParsers,
1322
})
1423

1524
/** Reads a link from before providers had their own route, so it can be sent there. */
1625
export const loadIntegrationView = createLoader({
17-
...organizationPageParsers,
26+
...integrationSearchParsers,
1827
...integrationViewParsers,
1928
})
2029

‎apps/sim/app/o/[organizationId]/integrations/secrets/page.tsx‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ import type { Metadata } from 'next'
22
import { createLoader, type SearchParams } from 'nuqs/server'
33
import { OrganizationSecretsPage } from '@/components/secrets/organization-secrets-page'
44
import { organizationRoutes } from '@/lib/navigation/paths'
5-
import { organizationPageParsers } from '@/app/o/[organizationId]/components/organization-page/search-params'
6-
import { serializeIntegrationView } from '@/app/o/[organizationId]/integrations/search-params'
5+
import {
6+
integrationSearchParsers,
7+
serializeIntegrationView,
8+
} from '@/app/o/[organizationId]/integrations/search-params'
79

810
export const metadata: Metadata = { title: 'Generic Secrets' }
911

@@ -12,7 +14,7 @@ interface MemberSecretsPageProps {
1214
searchParams: Promise<SearchParams>
1315
}
1416

15-
const loadSearch = createLoader(organizationPageParsers)
17+
const loadSearch = createLoader(integrationSearchParsers)
1618

1719
export default async function Page({ params, searchParams }: MemberSecretsPageProps) {
1820
const { organizationId } = await params

‎apps/sim/app/o/[organizationId]/integrations/utils.ts‎

Lines changed: 0 additions & 17 deletions
This file was deleted.

0 commit comments

Comments
 (0)