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

Suspensify PermissionsProvider using useWrappedQuery #21440

Closed

Conversation

salazarm
Copy link
Contributor

Summary & Motivation

Suspensify PermissionsProvider. Concretely this means instead of returning PermissionsResults, it instead returns a wrappedPromise (an object with a read method that suspends (throws a promise) if the data is not available).

The idea here is that we don't want PermissionsProvider itself to suspend because the route being rendered might not use the permission data at all, and because the route being rendered might want to make its own queries in parallel and if we suspended immediately it wouldn't get the chance to do that. Instead a child component reads the data after making their own suspended query and then calls the read function which would cause it to suspend.

How I Tested These Changes

Local dagster dev, navigate the app and make sure things that check permissions (like the assets table) are still correctly obtaining permissions

Copy link

github-actions bot commented Apr 26, 2024

Deploy preview for dagit-core-storybook ready!

✅ Preview
https://dagit-core-storybook-49o5gchwc-elementl.vercel.app
https://salazarm-suspensify-permissions-provider.core-storybook.dagster-docs.io

Built with commit f43e10c.
This pull request is being automatically deployed with vercel-action

Copy link
Collaborator

@bengotow bengotow left a comment

Choose a reason for hiding this comment

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

Left a few inline comments but nothing major!

</Route>
<Route path="/assets(/?.*)">
<Suspense fallback={<div />}>
<TrackedSuspense fallback={<div />} id={id('assets')}>
Copy link
Collaborator

Choose a reason for hiding this comment

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

I have two questions here:

  1. Why is it necessary to put the Suspense inside the Route and not inside the Switch on line 37? Does this really need to be repeated for every route separately like this? Is this primarily so the id can be passed?

  2. If the reason for Separate Pandas Dataframe Solid into Two Sources #1 is so that the suspense instance is replaced when you navigate, do these /* type routes all share the same tracked suspense? Is that ok?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's not necessary, I was just replacing the existing Suspense calls with TrackedSuspense in a follow up we can consolidate these but didn't want to unknowingly break anything by doing that

showCustomAlert({title: 'Error', body: <PythonErrorInfo error={backfill.error} />})
}
onClick={() => {
console.log('backfill error');
Copy link
Collaborator

Choose a reason for hiding this comment

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

rm?

onClick={() => {
console.log('backfill error');
if (backfill.error) {
console.log('Show custom alert');
Copy link
Collaborator

Choose a reason for hiding this comment

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

rm

rawUnscopedData: PermissionFragment[];
};

type PermissionsContextType = ReturnType<typeof wrapPromise<PermissionsResult>>;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would be nice for your wrapPromise util to expose a type helper that makes this Wrapped<PermissionsResult>, I expect we'll need this in a lot of places

Comment on lines +148 to +170
async (result) => {
const {data, error} = result;

const value = React.useMemo(() => {
const unscopedPermissionsRaw = data?.unscopedPermissions || [];
const unscopedPermissions = extractPermissions(unscopedPermissionsRaw);
const unscopedPermissionsRaw = data?.unscopedPermissions || [];
const unscopedPermissions = extractPermissions(unscopedPermissionsRaw);

const locationEntries =
data?.workspaceOrError.__typename === 'Workspace'
? data.workspaceOrError.locationEntries
: [];
const locationEntries =
data?.workspaceOrError.__typename === 'Workspace'
? data.workspaceOrError.locationEntries
: [];

const locationPermissions: Record<string, PermissionsMap> = {};
locationEntries.forEach((locationEntry) => {
const {name, permissions} = locationEntry;
locationPermissions[name] = extractPermissions(permissions, unscopedPermissionsRaw);
});
const locationPermissions: Record<string, PermissionsMap> = {};
locationEntries.forEach((locationEntry) => {
const {name, permissions} = locationEntry;
locationPermissions[name] = extractPermissions(permissions, unscopedPermissionsRaw);
});

return {
unscopedPermissions,
locationPermissions,
loading,
rawUnscopedData: unscopedPermissionsRaw,
};
}, [data, loading]);
return {
error,
unscopedPermissions,
locationPermissions,
rawUnscopedData: unscopedPermissionsRaw,
};
Copy link
Collaborator

Choose a reason for hiding this comment

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

This all looks good to me! Just from reading this it's not clear that the use of useWrapped has suspense implications, it sorta just looks like a stylistic change moving the data transform into the hook. Maybe we call out in the naming that this significantly changes the loading semantics.

@salazarm salazarm closed this Apr 29, 2024
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