optimistic-gold
optimistic-gold9mo ago

How to add a menu item in Sider with "create" action?

I need a confirmation of the fact that resource in <Refine> will only create "list" menu item correct? What would be the right way if I want to add custom menu item, with custom positioned and still have the CanAccess functionalities? Right now I have this file: import { AppstoreOutlined, MailOutlined, SettingOutlined } from '@ant-design/icons'; import type { MenuProps } from 'antd'; type MenuItem = Required<MenuProps>['items'][number]; export const customMenuItems: MenuItem[] = [ { label: "Navigation One", key: "1", icon: <MailOutlined />, children: [] } ]; And in my sider.tsx (which I created using Swizzle ThemedLayout for antd): const renderMenu = () => { return ( <Menu selectedKeys={selectedKey ? [selectedKey] : []} defaultOpenKeys={defaultOpenKeys} mode="inline" items={customMenuItems} > {logout} </Menu> ); }; It works with showing the item I added, but I know for sure renderTreeView with CanAccess (automatically generated using Swizzle) are not being implemented for my menu item
14 Replies
kapa.ai
kapa.ai9mo ago
Hi @lukevo.. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Yes, you're correct. In the <Refine> component, the resources property is used to create navigation links in the sider menu. Each resource with a list property set will have a corresponding menu item. To add a custom menu item and still have the CanAccess functionalities, you can use the render property of the <Sider> component. The render property is a function that receives an object with the items and logout properties. The items property is the list of navigation items and the logout property is the logout button. Here's an example of how to create a custom Sider with role-based menu items:
import { useCan } from "@refinedev/core";
import { Menu } from "@refinedev/antd";

const CustomSider = () => {
const { data: canViewMenuItem1 } = useCan({ resource: "menuItem1", action: "view" });
const { data: canViewMenuItem2 } = useCan({ resource: "menuItem2", action: "view" });

return (
<Menu>
{canViewMenuItem1?.can && <Menu.Item key="menuItem1">Menu Item 1</Menu.Item>}
{canViewMenuItem2?.can && <Menu.Item key="menuItem2">Menu Item 2</Menu.Item>}
</Menu>
);
};
import { useCan } from "@refinedev/core";
import { Menu } from "@refinedev/antd";

const CustomSider = () => {
const { data: canViewMenuItem1 } = useCan({ resource: "menuItem1", action: "view" });
const { data: canViewMenuItem2 } = useCan({ resource: "menuItem2", action: "view" });

return (
<Menu>
{canViewMenuItem1?.can && <Menu.Item key="menuItem1">Menu Item 1</Menu.Item>}
{canViewMenuItem2?.can && <Menu.Item key="menuItem2">Menu Item 2</Menu.Item>}
</Menu>
);
};
Then, pass the CustomSider component to the Layout component's Sider property:
import { Layout } from "@refinedev/core";
import CustomSider from "./CustomSider";

const App = () => {
return (
<Layout Sider={CustomSider}>
{/* Your app content */}
</Layout>
);
};
import { Layout } from "@refinedev/core";
import CustomSider from "./CustomSider";

const App = () => {
return (
<Layout Sider={CustomSider}>
{/* Your app content */}
</Layout>
);
};
In this example, the useCan hook is used to check if the user has the required permissions for each menu item. The useCan hook cannot be used outside of the <Refine> component, so it's used inside the CustomSider component. Sources: - Discord support thread: Role based Sider (https://discord.com/channels/837692625737613362/1121423983812812810) - Documentation > Docs > FAQ > How can I add an item to the Sider component? (https://refine.dev/docs/faq/#how-can-i-add-an-item-to-the-sider-component) ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai9mo ago
<@582491401715974144> kapa.ai is still learning and improving, please let us know how it did by reacting below
optimistic-gold
optimistic-gold9mo ago
warning.js:19 Warning: [antd: Menu] children is deprecated. Please use items instead. like <Menu items={customSider}> @kapa.ai
kapa.ai
kapa.ai9mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- The warning you're seeing is due to a deprecation notice from Ant Design's Menu component. It suggests that the children prop will be removed in the next major version and recommends using the items prop instead. However, as discussed in the Github issue (https://github.com/refinedev/refine/issues/1857), the items prop currently doesn't support async conditional rendering of the elements, which is a feature that the children prop provides. This is why the children prop is still being used in the Menu component in refine. If you want to suppress the warning, you can use the following code snippet before the Sider component is rendered:
const _error = console.error;

const itemsWarning = "`children` will be removed in next major version. Please use `items` instead.";

console.error = function (msg, ...args) {
if (!`${msg}`.includes(itemsWarning)) {
_error.apply(console, [msg, ...args]);
}
};
const _error = console.error;

const itemsWarning = "`children` will be removed in next major version. Please use `items` instead.";

console.error = function (msg, ...args) {
if (!`${msg}`.includes(itemsWarning)) {
_error.apply(console, [msg, ...args]);
}
};
This code overrides the console.error function to filter out the specific warning message. It's a temporary workaround until the antd library provides a better solution for the items prop or decides to keep the children prop. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai9mo ago
<@582491401715974144> kapa.ai is still learning and improving, please let us know how it did by reacting below
optimistic-gold
optimistic-gold9mo ago
Module '"@refinedev/antd"' has no exported member 'Menu'. @kapa.ai
kapa.ai
kapa.ai9mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- The error message "Module '@refinedev/antd' has no exported member 'Menu'" typically occurs when you're trying to import a component that doesn't exist in the '@refinedev/antd' package. In refine, the 'Menu' component is not exported from '@refinedev/antd'. Instead, you should import the 'Menu' component directly from 'antd'. Here's how you can do it:
import { Menu } from 'antd';
import { Menu } from 'antd';
If you're trying to use the 'Menu' component in the context of refine (for example, in a custom layout), you should use the components provided by the '@refinedev/antd' package that are designed to work with refine's features. If you're still facing issues, it might be due to an outdated version of the '@refinedev/antd' package. You can update it to the latest version by running the following command:
npm i @refinedev/antd@latest
npm i @refinedev/antd@latest
This should update the module to the latest version and resolve the "not exported" error. If the error persists, it might be due to an issue with the cache system of your package manager. In that case, try clearing the cache and reinstalling the dependencies. Sources: - Discord support thread: Uncaught SyntaxError: The requested module &x27;/node_modules/.vite/deps/@refinedev_antd.js?v=8efe8509&x27; > Answers (https://discord.com/channels/837692625737613362/1167394144650547200) - Documentation > Docs > FAQ > Module "X" has no exported member "Y" (https://refine.dev/docs/faq/#module-x-has-no-exported-member-y) ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai9mo ago
<@582491401715974144> kapa.ai is still learning and improving, please let us know how it did by reacting below
optimistic-gold
optimistic-gold9mo ago
I want to have a workaround method. Where I edit the source code of Refine so that it doesn't just only allow "list" action resource to be added in the menu but also "create" action @kapa.ai
kapa.ai
kapa.ai9mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- To modify the source code of Refine to allow "create" action resources to be added to the menu, you would need to modify the logic in the Sider component where it generates the menu items based on the resources prop of the <Refine> component. However, directly modifying the source code of a library is generally not recommended because it can lead to unexpected behavior and compatibility issues. It also makes it harder to update the library in the future. Instead, you can create a custom Sider component and pass it to the Layout component's Sider property. In your custom Sider component, you can generate the menu items based on your own logic. Here's an example of how to create a custom Sider component that includes "create" action resources in the menu:
import { Layout, useNavigation } from "@refinedev/core";
import { Menu } from "antd";

const CustomSider = () => {
const { resources } = useNavigation();

return (
<Menu>
{resources.map((resource) => (
<Menu.ItemGroup key={resource.name} title={resource.name}>
{resource.list && <Menu.Item key={`${resource.name}-list`}>List</Menu.Item>}
{resource.create && <Menu.Item key={`${resource.name}-create`}>Create</Menu.Item>}
</Menu.ItemGroup>
))}
</Menu>
);
};

const App = () => {
return (
<Layout Sider={CustomSider}>
{/* Your app content */}
</Layout>
);
};
import { Layout, useNavigation } from "@refinedev/core";
import { Menu } from "antd";

const CustomSider = () => {
const { resources } = useNavigation();

return (
<Menu>
{resources.map((resource) => (
<Menu.ItemGroup key={resource.name} title={resource.name}>
{resource.list && <Menu.Item key={`${resource.name}-list`}>List</Menu.Item>}
{resource.create && <Menu.Item key={`${resource.name}-create`}>Create</Menu.Item>}
</Menu.ItemGroup>
))}
</Menu>
);
};

const App = () => {
return (
<Layout Sider={CustomSider}>
{/* Your app content */}
</Layout>
);
};
In this example, the useNavigation hook is used to get the resources prop of the <Refine> component. Then, for each resource, a Menu.ItemGroup is created with a "List" and a "Create" menu item if the corresponding action is defined. Please note that this is a simplified example and you might need to adjust it to fit your needs. For example, you might want to add links to the menu items, handle active menu item state, etc. Sources: - Discord support thread: How to add Example pages? (https://discord.com/channels/837692625737613362/1135689992589561977) - Documentation > Docs > Tutorial > Understanding-resources > Resources > What is resource? (https://refine.dev/docs/tutorial/understanding-resources/index/#what-is-resource) - Documentation > Docs > Examples > Multi-level Menu (https://refine.dev/docs/examples/multi-level-menu/) - Documentation > Docs > Api-reference > Mui > Components > Basic-views > Create > Properties > resource (https://refine.dev/docs/api-reference/mui/components/basic-views/create/#resource) ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai9mo ago
<@582491401715974144> kapa.ai is still learning and improving, please let us know how it did by reacting below
optimistic-gold
optimistic-gold9mo ago
From my understanding this is ignoring a lot of the architechture of the Sider generated using swizzle for antd and refine which have very good implementation like CanAccess, automatically create child menu item, logout unsaved change,... So what I want is to modify the generated Sider that Swizzle give me by putting my own custom menu items or making "create" aciton resource available in the menu, either way I want to keep all of the mechanism in the default Sider @kapa.ai
kapa.ai
kapa.ai9mo ago
Let me check the knowledge base for you. One moment! :books: ---------------------- To modify the Sider generated by Swizzle while keeping all the existing functionalities, you can create a custom Sider component and use the render prop of the <Sider> component. The render prop is a function that receives an object with the items and logout properties. The items property is the list of navigation items and the logout property is the logout button. Here's an example of how you can add a "Create Order" item to the Sider:
import { Layout, Sider } from "@refinedev/antd";

const CustomSider = () => {
return (
<Sider
render={({ items, logout }) => {
return (
<>
{items}
<a href="/orders/create">Create Order</a>
{logout}
</>
);
}}
/>
);
};

const CustomLayout = () => {
return <Layout Sider={CustomSider}>...</Layout>;
};
import { Layout, Sider } from "@refinedev/antd";

const CustomSider = () => {
return (
<Sider
render={({ items, logout }) => {
return (
<>
{items}
<a href="/orders/create">Create Order</a>
{logout}
</>
);
}}
/>
);
};

const CustomLayout = () => {
return <Layout Sider={CustomSider}>...</Layout>;
};
In this example, a new navigation link "Create Order" is added to the Sider. When clicked, it will redirect to the create page of the "orders" resource. Please note that this is a simple example and you might need to adjust it according to your needs. For instance, you might want to style the new navigation link to make it look like the other items, or add some logic to only show it to certain users. If you want to add role-based access control to the new menu item, you can use the useCan hook or the <CanAccess /> component to check if the user has the required permissions to view the menu item. Sources: - Discord support thread: Customize sider with ant design (https://discord.com/channels/837692625737613362/1141901837738442935) - Documentation > Docs > FAQ > How can I add an item to the Sider component? (https://refine.dev/docs/faq/#how-can-i-add-an-item-to-the-sider-component) ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai9mo ago
<@582491401715974144> kapa.ai is still learning and improving, please let us know how it did by reacting below