-
-
Notifications
You must be signed in to change notification settings - Fork 5.3k
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
v4: resources not reloading after login or auth change #7527
Comments
Hi! Once again, thank you for submitting this. I am not sure this is really an issue with react admin, but rather with the actual implementation you used to test this feature. Anyway, I think that with a "real world" implementation, where your resources are not conditioned to the auth state but rather to a permission system (that you query after your are logged in), you wouldn't have this problem. But since it's a quite advanced mechanism, I would be happy to have @fzaninotto , @djhi or @WiXSL give their advice on this 🙂 |
@slax57 Hi! 😄 I just checked usePermissions and it also uses useSafeSetState. Whatever that is, based on what I know so far I'd say that it's doing something wrong. usePermissions and useAuthState offer information. When that information changes they should let me know. If my navitgation is based on those permissions and the auth state, how else should it be implemented?
I do this in the authProvider. It has a dedicated method for it that allows me to use existing systems (usePermissions). I'm also not sure how I'd write a permission system that checks permissions on login if I'm never being notified of changes in the auth state. Putting that logic in the login screen would be weird. Putting logic that triggers a rerender in a provider also doesn't strike me as usual. Anyway for reference here's a slightly larger code snippet (I can't share it all because contracts): function GuardedResources() {
const { isLoading, guard } = usePermissionGuard();
const composedResources = useMemo(() => {
if (isLoading || !guard.hasPermissions()) return null;
return resources.map(({ permissionResource: r, components, ...props }) => {
if (!guard.isAllowed(r)) return null;
return <Resource key={`r_${r}`} {...guard.filterComponents(r, components)} {...props} />;
});
}, [isLoading, guard]);
return (
<AdminUI layout={MyLayout} loginPage={SignIn} disableTelemetry={true} requireAuth>
{composedResources}
</AdminUI>
);
}
function App() {
return (
<AdminContext
authProvider={authProvider}
dataProvider={withUpload}
i18nProvider={defaultI18nProvider}
store={store}
>
<GuardedResources />
</AdminContext>
);
} Where usePermissionGuard is: import { useEffect, useMemo, useState } from 'react';
import { usePermissions } from 'react-admin';
import { PermissionGuard } from './PermissionGuard';
export function usePermissionGuard() {
const guard = useMemo(() => new PermissionGuard(), []);
const { isLoading, permissions } = usePermissions();
const [permissionGuard, setPermissionGuard] = useState({ isLoading, guard });
useEffect(() => {
guard.setPermissions(isLoading ? null : permissions?.permissions);
setPermissionGuard({ guard, isLoading });
}, [guard, isLoading, permissions]);
return permissionGuard;
} Some notes to help reading this:
export default {
permissionResource: 'Role',
name: 'roles',
icon: BadgeIcon,
components: new GuardedComponents([
['list', { action: 'GetList', component: RoleList }],
['show', { action: 'GetOne', component: RoleShow }],
['edit', { action: 'Update', component: RoleEdit }],
['create', { action: 'Create', component: RoleCreate }],
]),
} as ResourceDefinition; |
Okay. So I took some time to dive back into this issue. Here's what I've been able to find:
So this other example showcases that there is a refresh problem with the list of resources. I've been able to narrow this down to the So yeah, there probably is a bug somewhere around there, or at least something we could improve. I'll have a chat with the team to gather their opinion on this. Anyway, thanks for your submission 🙂 |
The bug is still there, let me reopen this issue. |
Hi! So, I took some time to dive in this issue, again 😅. Here are my conclusions:
According to me, the reason why it doesn't work in your test is because:
function GuardedResources() {
useEffect(() => {
console.log('GuardedResources - mounted');
return () => console.log('GuardedResources - unmounted!');
}, []);
const [state, setState] = useSafeSetState({
isLoading: true,
authenticated: true, // optimistic
});
const checkAuth = useCheckAuth();
checkAuth({}, false)
.then(() =>
setState(prev => {
if (!prev.authenticated || prev.isLoading)
return { isLoading: false, authenticated: true };
else return prev;
})
)
.catch(() =>
setState(prev => {
if (prev.authenticated || prev.isLoading)
return { isLoading: false, authenticated: false };
else return prev;
})
);
const { isLoading: authLoading, authenticated } = state;
console.log(`checkAuth result: { ${authLoading}, ${authenticated} }`);
if (authLoading || !authenticated) {
console.log('rendering empty');
return <AdminUI></AdminUI>;
}
console.log('rendering resources');
return (
<AdminUI>
<Resource name="posts" {...posts} />
<Resource name="comments" {...comments} />
<Resource name="users" {...users} />
<Resource name="tags" {...tags} />
</AdminUI>
);
} In conclusion, I believe there are several way to fix this (I mentioned some above), but I do not thing this deserves a fix at RA's side. Unless of course it turns out the Feel free to let me know what you think about this, especially if you disagree with my analysis 😅 |
Hooks is literally named as a reason to use the context in the docs I linked. Anyway it's fine, I just forked and fixed it for myself. It's why I closed this issue. |
@RWOverdijk you are, once again, totally right about the docs, I totally missed the part where you are encouraged to unplug the AdminContext and the AdminUI, sorry about that. Still, what I said about the Anyway, I'm glad you found a way to do it. If you believe it's worth sharing, feel free to add more details about your implementation here (or to do a PR) 🙂 Closing issue for now. Thanks again, and cheers |
It should be basic functionality to be able to secure your App and not obscenely complicated |
@howardjm It is, and we already provide several built-in solutions for that:
This issue is about a rather specific use-case if my recollection is good. |
What you were expecting:
When logging in I expect the resources to reload. The reason for this is that the auth state change comes with a permissions change, which decides which resources the user can view.
What happened instead:
The ready screen:
Steps to reproduce:
I followed this: https://marmelab.com/react-admin/doc/4.0/Admin.html#declaring-resources-at-runtime
It's really pretty simple to reproduce. Create a custom AdminContext and based on the auth state either render null or the resources (pretending you don't have permissions to see the other pages).
I made a sandbox based on the example in the repo (bnase sandbox: https://codesandbox.io/s/github/marmelab/react-admin/tree/next/examples/simple) but it's pretty difficult to get it to run on codesandbox (a dependency issue somewhere?). What I did:
Then, when in the browser follow these steps:
This is an example. I tried other things like forcing a re-render. It does rerender, it just doesn't register the resources.
Video of the issue demonstrated:
stuk.mov
Related code:
https://codesandbox.io/s/strange-greider-8eieup
Specifically in index.js:
This is the most basic example of what I'm actually trying to do which is load in permissions async and show resources based on them. Users are allowed to change their role while logged in (different profiles, like for example netflix). But something as basic as logging in already doesn't work and properly illustrates my issue I think.
Environment
The text was updated successfully, but these errors were encountered: