-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Svelte: unrevert RepoPopover
#62744
Svelte: unrevert RepoPopover
#62744
Conversation
b5660d3
to
c9faa79
Compare
@@ -109,5 +109,6 @@ | |||
border-radius: var(--popover-border-radius); | |||
color: var(--body-color); | |||
box-shadow: var(--popover-shadow); | |||
overflow: hidden; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small addition that ensures that the contents of the popover do not overflow the popover. Notably, this ensures that the border radius gets applied to any children as well (otherwise the corners of square children will overlap the border)
name | ||
description | ||
stars | ||
isPrivate | ||
language |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed language because this is calculated with inventory, which is stupidly expensive and flaky on large repos. This was regularly timing out for repos like llvm
.
As a more general conversation point: I do not think we should be implementing any features at this point that do not scale to large customers.
export async function fetchRepoPopoverData(client: GraphQLClient, repoName: string): Promise<RepoPopoverFragment> { | ||
const response = await client.query(RepoPopoverQuery, { repoName }) | ||
if (!response.data?.repository || response.error) { | ||
throw new Error(`Failed to fetch repo info: ${response.error}`) | ||
} | ||
return response.data.repository | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know this is controversial, but it was really pretty rough to thread this from page data, through every intermediate component, and finally into this component.
I think this strikes a good balance by colocating the definition of the data fetcher with the component that uses it, but not fetching the data on mount, which allows the caller to handle data fetching however it wants. In this case, we do not want to fetch the data on page load, and we also want to add a delay before rendering. That would not be possible if we fetched the data on mount inside the component.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but it was really pretty rough to thread this from page data, through every intermediate component, and finally into this component.
I suspected that this would happen eventually, and was hoping that when that time comes we know how we want to approach this.
I actually thought about this recently. I think there is kind of a forth type of data: on demand data that is unrelated (or only loosely related) to the current URL. For this kind of data it doesn't make sense to use the data loader. We will never preload the data and it's likely that this data (components) is needed (used) on multiple pages.
I arrived at a similar solution: These components would define a "loader" that handles the data loading for them and they would get passed an instance of the loader. This way we can still easily test the component and we are separating concerns. This was with more complex data loading in mind, e.g. infinity scroll.
In a case like this it seems fine to just have a function returning the results and pass those to the component.
So yeah, I think this approach is perfectly fine and we should use similar patterns for similar components.
Side note: The whole "only fetch data in data loader" principle was never meant to be absolute. It should help us understand what kind of data we are working with and determine appropriate exceptions to this rule.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This all makes sense to me! Thanks for adding some color 🙂
$: commit = data.commit | ||
$: author = commit?.author | ||
$: avatar = author?.person | ||
$: codeHostKind = data.externalServices.nodes[0].kind | ||
</script> | ||
|
||
<div class="root"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the component itself, I made a number of DOM and CSS simplifications, most of which did not affect rendering, a few of which fixed rendering for weird edge cases like empty description or long commit message.
// Returns a promise that is guaranteed to take at least `delayMillis` milliseconds to resolve. | ||
// If the wrapped promise resolves before then, the returned promise will wait until `delayMillis` | ||
// has elapsed before resolving. | ||
export async function delay<T>(promise: Promise<T>, delayMillis: number): Promise<T> { | ||
const [awaited] = await Promise.all([promise, new Promise(resolve => setTimeout(resolve, delayMillis))]) | ||
return awaited | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Small utility to delay resolution of a promise. We may want to add this as a general option on the Popover component, but I wanted to see how it feels first.
wip minimize divs and simplify layout/css wip fetching data not working hacky solution to the fetching problem design tweaks css tweaks popover stays visible when cursor moves toward or hovers over design tweaks and performance improvement fetch topics, not tags add useDefaultBorder option to Popover; optimize RepoPopover layout/style Popover content should control the border, not the popover itself lint and make changes from review use badges fetch repo popover data from RepoRev component remove interpunct between commit message and abbreviatedOID since it is not in the design spec remove unused imports lint remove comment revert popover changes simplify repo popover component remove duplicate border radius simplify and link to commit fix data loading behavior do not display empty popover add comment add more comments add delay drop divider, fix alignmet fix small fix spacing and colors delete redundant row nowrap appease linter
9df75e0
to
b8d0282
Compare
RepoPopover
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you!
export async function fetchRepoPopoverData(client: GraphQLClient, repoName: string): Promise<RepoPopoverFragment> { | ||
const response = await client.query(RepoPopoverQuery, { repoName }) | ||
if (!response.data?.repository || response.error) { | ||
throw new Error(`Failed to fetch repo info: ${response.error}`) | ||
} | ||
return response.data.repository | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but it was really pretty rough to thread this from page data, through every intermediate component, and finally into this component.
I suspected that this would happen eventually, and was hoping that when that time comes we know how we want to approach this.
I actually thought about this recently. I think there is kind of a forth type of data: on demand data that is unrelated (or only loosely related) to the current URL. For this kind of data it doesn't make sense to use the data loader. We will never preload the data and it's likely that this data (components) is needed (used) on multiple pages.
I arrived at a similar solution: These components would define a "loader" that handles the data loading for them and they would get passed an instance of the loader. This way we can still easily test the component and we are separating concerns. This was with more complex data loading in mind, e.g. infinity scroll.
In a case like this it seems fine to just have a function returning the results and pass those to the component.
So yeah, I think this approach is perfectly fine and we should use similar patterns for similar components.
Side note: The whole "only fetch data in data loader" principle was never meant to be absolute. It should help us understand what kind of data we are working with and determine appropriate exceptions to this rule.
This re-applies #61989 after it was reverted.
More detail inline, but in short:
Popover.svelte
that removed the border.Test plan
Storybook and lots of manual testing. Now that I'm writing this, we should probably add a playwright test too.