Skip to content

feat(ourlogs): implement pinned logs with sticky header#115102

Open
JoshuaKGoldberg wants to merge 18 commits into
masterfrom
ourlogs-pinned-logs-sticky
Open

feat(ourlogs): implement pinned logs with sticky header#115102
JoshuaKGoldberg wants to merge 18 commits into
masterfrom
ourlogs-pinned-logs-sticky

Conversation

@JoshuaKGoldberg
Copy link
Copy Markdown
Member

@JoshuaKGoldberg JoshuaKGoldberg commented May 7, 2026

Part 1 of 2 for implementation: rendering logs that are already available in data.

I have to admit, I don't particularly like this implementation. LogRowContent determines whether to render pin UI by whether useLogsPinning() returns a context value, which happens only if a provider is available. I would have preferred to DI / props drill from the parent page -> LogsInfiniteTable. But there's a lot going on and I couldn't quite make it work nicely 😞. As a followup to all this work & the logs table constrained heights (LOGS-664), I'd like even more to refactor a bunch.

Note that this doesn't handle fetching pinned logs that aren't yet available in the virtualized list data or removing pinned logs from the query parameters on query changes. That'll be part 2 of 2: LOGS-781.

Fixes LOGS-776.

Takes inspiration and a healthy amount of code from #114922. Therefore:

Co-authored-by: @marthalyndon

@JoshuaKGoldberg JoshuaKGoldberg requested a review from a team as a code owner May 7, 2026 18:55
@linear-code
Copy link
Copy Markdown

linear-code Bot commented May 7, 2026

LOGS-651

LOGS-776

@github-actions github-actions Bot added the Scope: Frontend Automatically applied to PRs that change frontend components label May 7, 2026
Comment thread static/app/views/explore/logs/tables/logsTableRow.tsx
Comment thread static/app/views/explore/logs/pinning/PinnedLogs.tsx Outdated
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 7, 2026

📊 Type Coverage Diff

✅ No new type safety issues introduced. Coverage: 93.51%

Comment thread static/app/views/explore/logs/tables/logsTableRow.tsx
Comment thread static/app/views/explore/logs/tables/logsTableRow.tsx Outdated
Comment thread static/app/views/explore/logs/pinning/useLogsPinning.tsx Outdated
Comment thread static/app/views/explore/logs/styles.tsx Outdated
Comment thread static/app/views/explore/logs/tables/logsTableRow.tsx
Comment thread static/app/views/explore/logs/tables/logsTableRow.tsx
Comment thread static/app/views/explore/logs/tables/logsTableRow.tsx Outdated
Comment thread static/app/views/explore/logs/pinning/useOurLogsPinning.tsx
Comment thread static/app/views/explore/logs/pinning/useLogsPinning.tsx Outdated
Comment thread static/app/views/explore/logs/tables/logsTableRow.tsx Outdated
Comment thread static/app/views/explore/logs/pinning/useLogsPinning.tsx
Comment thread static/app/views/discover/table/cellAction.tsx
Comment thread static/app/views/explore/logs/tables/logsTableRow.tsx
@JoshuaKGoldberg JoshuaKGoldberg requested a review from a team as a code owner May 8, 2026 16:09
}

interface RenderOptions extends rtl.RenderOptions, ProviderOptions {
export interface RenderOptions extends rtl.RenderOptions, ProviderOptions {
Copy link
Copy Markdown
Member Author

@JoshuaKGoldberg JoshuaKGoldberg May 8, 2026

Choose a reason for hiding this comment

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

[Explanation] Cursor keeps trying to add a Parameters<typeof render>[1], so I just exported this.

Comment thread static/app/views/explore/logs/tables/logsTableRow.tsx
Comment thread static/app/views/explore/logs/tables/logsTableRow.tsx
} else {
expect(actionsButton).toBeInTheDocument();
}
expect(actionsButton).toBeInTheDocument();
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is also in #115180.

Comment thread static/app/views/explore/logs/tables/logsTableRow.tsx
@JoshuaKGoldberg JoshuaKGoldberg requested a review from k-fish May 8, 2026 16:53
Copy link
Copy Markdown
Member

@k-fish k-fish left a comment

Choose a reason for hiding this comment

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

Perf is the only thing I think we should double check, maybe the comment re: LOGS-781, rest is nits.

Comment thread static/app/views/explore/logs/tables/logsTableRow.tsx
? `${window.location.pathname}?${newSearch}${window.location.hash}`
: `${window.location.pathname}${window.location.hash}`;

window.history.replaceState(window.history.state, '', newUrl);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

replaceState? 😬

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Blurgh. yeah. What is the recommended way to do this in our infra? I was getting lost in a lot of the shared utils.

Copy link
Copy Markdown
Member Author

@JoshuaKGoldberg JoshuaKGoldberg May 13, 2026

Choose a reason for hiding this comment

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

Ok I took another stab and ended up with ca0602a. I dislike this very much. It's convincing me that Solid.js-style fine-grained reactivity actually is much better (prior to now I didn't feel strongly one way or another). But if we have a better thing, that'd be nice 🙃.

Edit: also this causes #115102 (comment), so that's unfortunate.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Oh hey #115427 - @ryan953 this kind of intersects. What would you recommend here?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Taking a quick look at useLogsPinning.tsx looks like it's a bit recursive at this moment, if not actually recursive then doing too much imo. It's reading from location and setting pinnedRows as state, then the useEffect is calling navigate to update the location again...

try to use nuqs for all this, the location should be the source of truth and you probably don't need to stick default values into the url on pageload. it makes the urls messy and next pageload we'll just sort out the defaults again.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

#115427 removes some indirection that is absolutely never needed. i've left stuff like REPLAY_QUERY_KEY in there because i'm trying to automate things and want the bot doing one thing at a time, but it's ripe for removal next.

Comment on lines +335 to +336
data-row-pinned={isPinned}
data-row-hover-linked={isHoverLinked}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Are these just to avoid doing emotion's prop syntax?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I was going off the existing data-row-highlighted code. I could have sworn there was guidance saying explicitly to do this, but I can't find it now.

Is there a different preferred thing?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

No was just wondering why you were passing down data attributes, we might have a rule like that (I can't recall) but if so it's likely because of perf, so feel free to leave it

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Talked 1:1: we can switch both data-*s to standard props in LogTableRowProps.

The original thought was that there's another pattern of putting data-* props on a parent component for purely stylistic things. That lets us avoid child component rerenders. But we aren't benefitting from that here.

Comment thread static/app/views/explore/logs/tables/logsInfiniteTable.tsx Outdated
Comment thread static/app/views/explore/logs/pinning/PinnedLogs.tsx
Comment thread static/app/views/explore/logs/tables/logsInfiniteTable.tsx
Comment thread static/app/views/explore/logs/pinning/useLogsPinning.tsx Outdated
Comment thread static/app/views/explore/logs/tables/logsTableRow.tsx
Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ef75c37. Configure here.

Comment thread static/app/views/explore/logs/tables/logsTableRow.tsx Outdated
Comment on lines +53 to +63
...location,
query: {
...location.query,
[LOGS_PINNED_KEY]: Array.from(pinnedRows),
},
},
{replace: true}
);
// location is intentionally omitted — we only want to sync pinnedRows to the URL.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [navigate, pinnedRows]);
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.

Bug: The useEffect in LogsPinningProvider uses a stale location object, causing user-applied filters to be reverted when a row is pinned.
Severity: HIGH

Suggested Fix

To prevent using a stale location object, you can either include location in the useEffect dependency array, use a useRef to store and access the latest location, or conditionally render the LogsPinningProvider only when its feature flag is enabled. The goal is to ensure the navigate call always uses the most current URL query parameters when updating the URL with pinned row information.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: static/app/views/explore/logs/pinning/useLogsPinning.tsx#L50-L63

Potential issue: The `LogsPinningProvider` component captures the `location` object on
its initial render but intentionally omits it from the dependency array of a `useEffect`
hook. This hook is responsible for synchronizing pinned rows to the URL. If a user
modifies URL query parameters (e.g., by applying a search filter) and then pins a log
row, the `useEffect` triggers. It then calls `navigate` using the stale `location`
object captured on mount, which overwrites the user's current filters and reverts them
to their initial state, leading to incorrect data being displayed.

Also affects:

  • static/app/views/explore/logs/tables/logsInfiniteTable.tsx:483~489

Comment on lines +61 to +63
// location is intentionally omitted — we only want to sync pinnedRows to the URL.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [navigate, pinnedRows]);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't really like this hook rule but I understand why it's in place, Tony and I were cheekily using useBox on values that weren't meant to be deps instead of having a eslint ignore, but I'm not sure I like that extra fiber usage either 😆


const rowId = String(dataRow[OurLogKnownFieldKey.ID]);
const expansionKey = expansionKeyProp ?? rowId;
const logsPinning = useLogsPinning();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Okay, so this won't go crazy on hovers, but this WILL make the pinning click still a bit hefty... only way to fix this off the top of my head is to do orchestration one level higher above the rows to not break the memo and maybe containment (pass pinned) versions only if it applies to that row? A bit unwieldly but if this lags food for thought in the future.

@JoshuaKGoldberg
Copy link
Copy Markdown
Member Author

Talked 1:1: will do the LogTableRowProps, then merge

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Scope: Frontend Automatically applied to PRs that change frontend components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants