Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade and virtualize table component #8157

Merged
merged 7 commits into from
Jan 5, 2025
Merged

Conversation

hmacr
Copy link
Collaborator

@hmacr hmacr commented Dec 28, 2024

This PR virtualizes the Table component to fetch and show more data on scroll instead of prev/back buttons. Along the way, react-table library is upgraded to the latest version (tanstack/react-table).

For virtualization, tanstack/react-virtual is used instead of the existing react-window library.
tanstack/react-virtual APIs are more modern and more importantly, it uses transform to show/hide virtualized items (react-window uses top - we should replace its existing usages).

@hmacr hmacr requested a review from tommoor December 28, 2024 00:27
app/scenes/Settings/components/PeopleTable.tsx Outdated Show resolved Hide resolved
app/scenes/Settings/components/SharesTable.tsx Outdated Show resolved Hide resolved
server/routes/api/shares/shares.ts Outdated Show resolved Hide resolved
Copy link
Member

@tommoor tommoor left a comment

Choose a reason for hiding this comment

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

I noticed that there's some extra double scrolling going on now… Ideally it would appear like a normal settings page that just scrolls forever. If that's too hard with the virtualization then the main page scrolling could be fixed, but either way there shouldn't be multiple scroll areas :)

server/routes/api/shares/shares.ts Outdated Show resolved Hide resolved
app/scenes/Settings/components/PeopleTable.tsx Outdated Show resolved Hide resolved
app/scenes/Settings/components/SharesTable.tsx Outdated Show resolved Hide resolved
@hmacr
Copy link
Collaborator Author

hmacr commented Dec 29, 2024

I noticed that there's some extra double scrolling going on now

Oh, I think the table height needs adjusting. I intentionally fixed the page height so that only the table area is scrollable. That way, the filters at the top are always accessible.

Ideally it would appear like a normal settings page that just scrolls forever. If that's too hard with the virtualization then the main page scrolling could be fixed

Both should be doable.
I prefer a fixed main page scroll - do you prefer to keep the existing behaviour of the whole page scroll?

@hmacr hmacr requested a review from tommoor December 30, 2024 09:11
@tommoor
Copy link
Member

tommoor commented Dec 30, 2024

I prefer a fixed main page scroll - do you prefer to keep the existing behaviour of the whole page scroll?

In a perfect world it would be a full page scroll as that then triggers the sticky header instead of having the top 30% of the screen be used up by the header.

Otherwise this is great though, thanks

@hmacr
Copy link
Collaborator Author

hmacr commented Dec 30, 2024

In a perfect world it would be a full page scroll as that then triggers the sticky header instead of having the top 30% of the screen be used up by the header

Couldn't agree more! I tried that initially but it was very tricky to get it right for table and absolute positioned elements (quite a few quirks for table in CSS spec). An alternative we can try is to replace tables with divs and aria roles. That might help a lot in navigating these quirks. Is that something we can explore?

@tommoor
Copy link
Member

tommoor commented Dec 30, 2024

Happy to explore that if the table is the limiting factor

@hmacr
Copy link
Collaborator Author

hmacr commented Jan 3, 2025

I just pushed a commit that implements the full page scroll, please test and let me know if something needs to be changed 😄

}: Props) => {
const { t } = useTranslation();
const searchInputRef = React.useRef<HTMLInputElement>(null);
const listRef = React.useRef<HTMLDivElement | null>(null);
const menu = useMenuState({
modal: true,
modal: modalMenu ?? true,
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Quirks of reakit.. scroll position changes unexpectedly when opening the menu in modal mode
ariakit/ariakit#856 - Seems this issue is fixed in v2; all the more reason to move to Radix soon.

Copy link
Member

Choose a reason for hiding this comment

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

Ok, I guess my only thought is can we just default this to false then and avoid the prop drilling? It's not used in many spots

Copy link
Collaborator Author

@hmacr hmacr Jan 4, 2025

Choose a reason for hiding this comment

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

With modal true, the tab focus stays within the rendered menu - it may not be as important in this case I think.
Will change it 👍

Copy link
Member

@tommoor tommoor left a comment

Choose a reason for hiding this comment

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

v good

@@ -21,6 +21,8 @@ type Props = {
wide?: boolean;
/** The content of the scene */
children?: React.ReactNode;
/** Whether to shrink padding */
shrink?: boolean;
Copy link
Member

@tommoor tommoor Jan 3, 2025

Choose a reason for hiding this comment

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

I'm not really clear on how this differs from the wide option – aka when would we use one without the other? Would prefer to avoid shrink if wide can suffice.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah, this is not needed now..
Earlier, with the fixed height table, this was needed to reduce the bottom padding (and hence the body scroll).

}: Props) => {
const { t } = useTranslation();
const searchInputRef = React.useRef<HTMLInputElement>(null);
const listRef = React.useRef<HTMLDivElement | null>(null);
const menu = useMenuState({
modal: true,
modal: modalMenu ?? true,
Copy link
Member

Choose a reason for hiding this comment

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

Ok, I guess my only thought is can we just default this to false then and avoid the prop drilling? It's not used in many spots


const appName = env.APP_NAME;
React.useEffect(() => {
const timeout = setTimeout(() => updateParams("query", query), 250);
Copy link
Member

Choose a reason for hiding this comment

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

Why the timeout? Probably fine but worth a comment

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It's more of a "hacky" debounce for the filter typed in the search box (earlier, we were invoking the API for each keypress).

@tommoor
Copy link
Member

tommoor commented Jan 3, 2025

image

Oop, just spotted the sticky filters are infront of dialogs

@hmacr hmacr requested a review from tommoor January 4, 2025 00:46
@tommoor tommoor merged commit 9bc1788 into main Jan 5, 2025
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants