Skip to content

Commit ce234f4

Browse files
committed
fix(log-view): keep the tab local when the host wired no setter
Cursor caught a real regression, and it was mine. The execution slideout forwarded the table's `host` into `LogView` while deliberately passing no `tab`/`onTabChange` — so on the tables page `hostOwnsUrl` was true, `activeTab` was pinned to `tab ?? 'overview'`, and `setActiveTab` called an undefined callback. The Trace tab was unreachable when opening a run from the tables page. The panel host was unaffected, which is why the suite stayed green. The slideout's own TSDoc already claimed the tab stayed local. The doc described the intent; forwarding `host` contradicted it. Fixed at both levels: - The slideout mounts the log as `host='panel'` outright and no longer takes a `host` prop. A run slid in beside a table is embedded no matter where that table renders — it has no address on either surface, so the tab is local state by definition, not by inheritance from whatever the table happens to be. - `LogView` treats the tab as URL-owned only when the host actually wired the controlled pair (`hostOwnsUrl(host) && onTabChange !== undefined`). A host that owns its URL but supplies no setter is embedding this view somewhere unaddressable; degrading to local state keeps the tabs working. Dead tabs are strictly worse than a tab that does not persist. The guard rather than a discriminated union on `host`, because the table passes `host` as a variable — a type-level union would not have fired at that mount. Suite: 20951 passed.
1 parent 354c6df commit ce234f4

3 files changed

Lines changed: 18 additions & 9 deletions

File tree

apps/sim/components/resources/log-view/log-view.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,15 @@ export function LogView({
324324
* through `tab`/`onTabChange`; an embedded one keeps it local, so the panel
325325
* stops writing an unnamespaced key into its host's address bar.
326326
*/
327-
const urlOwned = hostOwnsUrl(host)
327+
/**
328+
* URL-owned only when the host actually wired the controlled pair. A host that
329+
* owns its URL but passes no `onTabChange` is not deep-linking the tab — it is
330+
* embedding this view somewhere unaddressable (the tables page's execution
331+
* slideout), and treating it as controlled would leave `activeTab` pinned to
332+
* the default with a setter that no-ops. Degrading to local state keeps the
333+
* tabs working; dead tabs are strictly worse than a tab that does not persist.
334+
*/
335+
const urlOwned = hostOwnsUrl(host) && onTabChange !== undefined
328336
const [localTab, setLocalTab] = useState<LogViewTab>('overview')
329337
const activeTab = urlOwned ? (tab ?? 'overview') : localTab
330338
const setActiveTab = useCallback(

apps/sim/components/resources/table-view/components/execution-slideout/execution-slideout.tsx

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { X } from '@sim/emcn/icons'
66
import { LogView } from '@/components/resources/log-view'
77
import type { WorkflowLogRow } from '@/lib/api/contracts/logs'
88
import { useLogDetailsResize } from '@/hooks/use-log-details-resize'
9-
import { type ResourceGrants, type ResourceHost, workspaceSource } from '@/resources'
9+
import { type ResourceGrants, workspaceSource } from '@/resources'
1010
import { useLogDetailsUIStore } from '@/stores/logs/store'
1111
import { MAX_LOG_DETAILS_WIDTH_RATIO, MIN_LOG_DETAILS_WIDTH } from '@/stores/logs/utils'
1212

@@ -16,7 +16,6 @@ interface ExecutionSlideoutProps {
1616
onClose: () => void
1717
workspaceId: string
1818
grants: ResourceGrants
19-
host: ResourceHost
2019
/**
2120
* Whether this viewer may see trace internals. Required, not
2221
* optional-defaulting-to-true: forgetting it must fail to compile rather than
@@ -35,9 +34,13 @@ interface ExecutionSlideoutProps {
3534
* `useQueryState` and the permission context — four route couplings a table has
3635
* no use for — and it deep-links its active tab, which meant opening a run from
3736
* the tables page wrote `?tab` onto the tables URL, and onto the host page's URL
38-
* from the chat panel. This slideout omits `tab`/`onTabChange` entirely, so the
39-
* view keeps the tab local, which is correct for a panel that was never
40-
* addressable.
37+
* from the chat panel. This slideout omits `tab`/`onTabChange` entirely and
38+
* mounts the log as `host='panel'` — deliberately NOT the host the table itself
39+
* is on. A run slid in beside a table is embedded no matter where that table
40+
* renders: it has no address of its own on either surface, so its tab must stay
41+
* local state. Forwarding the table's host instead made `hostOwnsUrl` true on
42+
* the tables page, where the view then read a `tab` prop nobody passes and the
43+
* Trace tab became unreachable.
4144
*
4245
* Only the chrome is reproduced: the frame, the resize handle, and a close
4346
* button. The logs page's prev/next and retry controls belong to a list this
@@ -49,7 +52,6 @@ export function ExecutionSlideout({
4952
onClose,
5053
workspaceId,
5154
grants,
52-
host,
5355
showExecutionInternals,
5456
onNavigate,
5557
}: ExecutionSlideoutProps) {
@@ -99,7 +101,7 @@ export function ExecutionSlideout({
99101
<LogView
100102
source={source}
101103
grants={grants}
102-
host={host}
104+
host='panel'
103105
log={log}
104106
showExecutionInternals={showExecutionInternals}
105107
onNavigate={handleNavigate}

apps/sim/components/resources/table-view/table-view.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1599,7 +1599,6 @@ export function TableView({
15991599
onClose={onCloseSlideout}
16001600
workspaceId={workspaceId}
16011601
grants={grants}
1602-
host={host}
16031602
showExecutionInternals={showExecutionInternals}
16041603
onNavigate={onNavigate}
16051604
/>

0 commit comments

Comments
 (0)