From 74b286b7011c8217779190091cf737799eb241ca Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Mon, 14 Oct 2024 10:18:38 +0300 Subject: [PATCH] docs: added documentation for admin components (#9491) - Documented common admin components with design that matches the admin. - Updated existing admin customization snippets to match the admin's design. Closes DOCS-964 --- .../app/advanced-development/admin/page.mdx | 6 + .../advanced-development/admin/tips/page.mdx | 4 +- .../admin/ui-routes/page.mdx | 48 +- .../admin/widgets/page.mdx | 20 +- .../app/basics/admin-customizations/page.mdx | 17 +- .../customize-admin/route/page.mdx | 44 +- .../customize-admin/widget/page.mdx | 10 +- www/apps/book/generated/edit-dates.mjs | 14 +- .../components/action-menu/page.mdx | 271 ++++++++ .../components/container/page.mdx | 65 ++ .../components/forms/page.mdx | 584 ++++++++++++++++++ .../components/header/page.mdx | 191 ++++++ .../components/json-view-section/page.mdx | 236 +++++++ .../components/section-row/page.mdx | 119 ++++ .../components/table/page.mdx | 245 ++++++++ .../layouts/single-column/page.mdx | 70 +++ .../layouts/two-column/page.mdx | 89 +++ .../resources/app/admin-components/page.mdx | 27 + www/apps/resources/generated/edit-dates.mjs | 10 + www/apps/resources/generated/files-map.mjs | 40 ++ www/apps/resources/generated/sidebar.mjs | 387 +++++++----- www/apps/resources/sidebar.mjs | 129 ++-- 22 files changed, 2385 insertions(+), 241 deletions(-) create mode 100644 www/apps/resources/app/admin-components/components/action-menu/page.mdx create mode 100644 www/apps/resources/app/admin-components/components/container/page.mdx create mode 100644 www/apps/resources/app/admin-components/components/forms/page.mdx create mode 100644 www/apps/resources/app/admin-components/components/header/page.mdx create mode 100644 www/apps/resources/app/admin-components/components/json-view-section/page.mdx create mode 100644 www/apps/resources/app/admin-components/components/section-row/page.mdx create mode 100644 www/apps/resources/app/admin-components/components/table/page.mdx create mode 100644 www/apps/resources/app/admin-components/layouts/single-column/page.mdx create mode 100644 www/apps/resources/app/admin-components/layouts/two-column/page.mdx create mode 100644 www/apps/resources/app/admin-components/page.mdx diff --git a/www/apps/book/app/advanced-development/admin/page.mdx b/www/apps/book/app/advanced-development/admin/page.mdx index 5e4bf62452..876a765ecd 100644 --- a/www/apps/book/app/advanced-development/admin/page.mdx +++ b/www/apps/book/app/advanced-development/admin/page.mdx @@ -18,3 +18,9 @@ You can customize the admin dashboard by: Medusa provides a Medusa UI package to facilitate your admin development through ready-made components and ensure a consistent design between your customizations and the dashboard’s design. Refer to the [Medusa UI documentation](https://docs.medusajs.com/ui) to learn how to install it and use its components. + +--- + +## Admin Components List + +To build admin customizations that match the Medusa Admin's designs and layouts, refer to [this guide](!resources!/admin-component) to find common components. diff --git a/www/apps/book/app/advanced-development/admin/tips/page.mdx b/www/apps/book/app/advanced-development/admin/tips/page.mdx index ca7179c5f8..25d3bb0631 100644 --- a/www/apps/book/app/advanced-development/admin/tips/page.mdx +++ b/www/apps/book/app/advanced-development/admin/tips/page.mdx @@ -41,7 +41,7 @@ const ProductWidget = () => { }, [loading]) return ( - + {loading && Loading...} {!loading && You have {productsCount} Product(s).} @@ -78,7 +78,7 @@ import { Link } from "react-router-dom" // The widget const ProductWidget = () => { return ( - + View Orders ) diff --git a/www/apps/book/app/advanced-development/admin/ui-routes/page.mdx b/www/apps/book/app/advanced-development/admin/ui-routes/page.mdx index d65830a203..3190b14d30 100644 --- a/www/apps/book/app/advanced-development/admin/ui-routes/page.mdx +++ b/www/apps/book/app/advanced-development/admin/ui-routes/page.mdx @@ -21,10 +21,16 @@ A UI route is created in a file named `page.tsx` under the `src/admin/routes` di For example, create the file `src/admin/routes/custom/page.tsx` with the following content: ```tsx title="src/admin/routes/custom/page.tsx" -import { Container } from "@medusajs/ui" +import { Container, Heading } from "@medusajs/ui" const CustomPage = () => { - return This is my custom route + return ( + +
+ This is my custom route +
+
+ ) } export default CustomPage @@ -59,17 +65,23 @@ A UI route file can export a configuration object that indicates a new item must For example: export const highlights = [ - ["14", "label", "The label of the UI route's sidebar item."], - ["15", "icon", "The icon of the UI route's sidebar item."] + ["16", "label", "The label of the UI route's sidebar item."], + ["17", "icon", "The icon of the UI route's sidebar item."] ] -```tsx title="src/admin/routes/custom/page.tsx" highlights={[["21"], ["22"], ["23"], ["24"], ["25"], ["26"]]} +```tsx title="src/admin/routes/custom/page.tsx" highlights={highlights} import { defineRouteConfig } from "@medusajs/admin-sdk" import { ChatBubbleLeftRight } from "@medusajs/icons" -import { Container } from "@medusajs/ui" +import { Container, Heading } from "@medusajs/ui" const CustomPage = () => { - return This is my custom route + return ( + +
+ This is my custom route +
+
+ ) } export const config = defineRouteConfig({ @@ -101,8 +113,10 @@ import { Container, Heading } from "@medusajs/ui" const CustomSettingPage = () => { return ( - - Custom Setting Page + +
+ Custom Setting Page +
) } @@ -124,14 +138,20 @@ A UI route can accept path parameters if the name of any of the directories in i For example, create the file `src/admin/routes/custom/[id]/page.tsx` with the following content: -```tsx title="src/admin/routes/custom/[id]/page.tsx" highlights={[["5", "", "Retrieve the path parameter."], ["7", "{id}", "Show the path parameter."]]} +```tsx title="src/admin/routes/custom/[id]/page.tsx" highlights={[["5", "", "Retrieve the path parameter."], ["10", "{id}", "Show the path parameter."]]} import { useParams } from "react-router-dom" import { Container } from "@medusajs/ui" const CustomPage = () => { const { id } = useParams() - return Passed ID: {id} + return ( + +
+ Passed ID: {id} +
+
+ ) } export default CustomPage @@ -140,3 +160,9 @@ export default CustomPage You access the passed parameter using `react-router-dom`'s [useParams hook](https://reactrouter.com/en/main/hooks/use-params). If you run the Medusa application and go to `localhost:9000/app/custom/123`, you'll see `123` printed in the page. + +--- + +## Admin Components List + +To build admin customizations that match the Medusa Admin's designs and layouts, refer to [this guide](!resources!/admin-component) to find common components. diff --git a/www/apps/book/app/advanced-development/admin/widgets/page.mdx b/www/apps/book/app/advanced-development/admin/widgets/page.mdx index a1ae8871f6..f811965bf6 100644 --- a/www/apps/book/app/advanced-development/admin/widgets/page.mdx +++ b/www/apps/book/app/advanced-development/admin/widgets/page.mdx @@ -24,7 +24,7 @@ For example, create the file `src/admin/widgets/product-widget.tsx` with the fol export const widgetHighlights = [ ["5", "ProductWidget", "The React component of the product widget."], - ["15", "zone", "The zone to inject the widget to."] + ["17", "zone", "The zone to inject the widget to."] ] ```tsx title="src/admin/widgets/product-widget.tsx" highlights={widgetHighlights} @@ -34,8 +34,10 @@ import { Container, Heading } from "@medusajs/ui" // The widget const ProductWidget = () => { return ( - - Product Widget + +
+ Product Widget +
) } @@ -85,7 +87,7 @@ For example: export const detailHighlights = [ ["10", "data", "Receive the data as a prop."], ["11", "AdminProduct", "Pass the expected type of `data` as a type argument."], - ["15", "data.title"] + ["16", "data.title", "Show the product's title."] ] ```tsx title="src/admin/widgets/product-widget.tsx" highlights={detailHighlights} @@ -101,10 +103,12 @@ const ProductWidget = ({ data, }: DetailWidgetProps) => { return ( - - - Product Widget {data.title} - + +
+ + Product Widget {data.title} + +
) } diff --git a/www/apps/book/app/basics/admin-customizations/page.mdx b/www/apps/book/app/basics/admin-customizations/page.mdx index b1be598aaf..e54b575b03 100644 --- a/www/apps/book/app/basics/admin-customizations/page.mdx +++ b/www/apps/book/app/basics/admin-customizations/page.mdx @@ -24,12 +24,15 @@ For example, create the file `src/admin/widgets/product-widget.tsx` with the fol ```tsx title="src/admin/widgets/product-widget.tsx" import { defineWidgetConfig } from "@medusajs/admin-sdk" +import { Container, Heading } from "@medusajs/ui" const ProductWidget = () => { return ( -
-

Product Widget

-
+ +
+ Product Widget +
+
) } @@ -42,6 +45,8 @@ export default ProductWidget This inserts a widget with the text “Product Widget” at the beginning of a product’s details page. +In your widget, use custom components from the [Medusa UI package](https://docs.medusajs.com/ui). + ### Test the Widget To test out the widget, start the Medusa application: @@ -51,3 +56,9 @@ npm run dev ``` Then, open a product’s details page in the Medusa Admin. You’ll find your custom widget at the top of the page. + +--- + +## Admin Components List + +To build admin customizations that match the Medusa Admin's designs and layouts, refer to [this guide](!resources!/admin-component) to find common components. diff --git a/www/apps/book/app/customization/customize-admin/route/page.mdx b/www/apps/book/app/customization/customize-admin/route/page.mdx index 74d8397122..f54975d61c 100644 --- a/www/apps/book/app/customization/customize-admin/route/page.mdx +++ b/www/apps/book/app/customization/customize-admin/route/page.mdx @@ -116,24 +116,28 @@ const BrandsPage = () => { return ( - - Brands - - - - ID - Name - - - - {brands.map((brand) => ( - - {brand.id} - {brand.name} + +
+ Brands +
+
+
+ + + ID + Name - ))} - -
+ + + {brands.map((brand) => ( + + {brand.id} + {brand.name} + + ))} + + +
) } @@ -147,6 +151,12 @@ This adds a new page in the admin at `http://localhost:9000/app/brands`. In the UI route's component, you retrieve the brands from the `/admin/brands` API route. You show the brands in a table. + + +Admin customizations can use the [Medusa UI package](!ui!) to align your customizations with the admin's design. Also, [this guide](!resources!/admin-components) includes examples of common components in the Medusa Admin. + + + ### Add UI Route to the Sidebar To add the UI route to the sidebar, replace the `TODO` at the end of the file with the following: diff --git a/www/apps/book/app/customization/customize-admin/widget/page.mdx b/www/apps/book/app/customization/customize-admin/widget/page.mdx index a1c10153e1..e4b4cea99d 100644 --- a/www/apps/book/app/customization/customize-admin/widget/page.mdx +++ b/www/apps/book/app/customization/customize-admin/widget/page.mdx @@ -29,7 +29,7 @@ export const highlights = [ ["7", "data", "Receive the product's details as a prop"], ["9", "brand", "A state variable to store the brand"], ["19", "fetch", "Retrieve the brand of a product using the custom API route"], - ["39", "zone", "Show the widget at the top of the product details page."] + ["41", "zone", "Show the widget at the top of the product details page."] ] ```tsx title="src/admin/widgets/product-brand.tsx" highlights={highlights} @@ -62,8 +62,10 @@ const ProductBrandWidget = ({ }, [loading]) return ( - - Brand + +
+ Brand +
{loading && Loading...} {brand && Name: {brand.name}}
@@ -91,7 +93,7 @@ In the widget, you fetch the product's brand from the `/admin/products/:id/brand -Admin customizations can use the [Medusa UI package](!ui!) to align your customizations with the admin's design. +Admin customizations can use the [Medusa UI package](!ui!) to align your customizations with the admin's design. Also, [this guide](!resources!/admin-components) includes examples of common components in the Medusa Admin. diff --git a/www/apps/book/generated/edit-dates.mjs b/www/apps/book/generated/edit-dates.mjs index cc6f0fc170..d7b0ee26d5 100644 --- a/www/apps/book/generated/edit-dates.mjs +++ b/www/apps/book/generated/edit-dates.mjs @@ -12,7 +12,7 @@ export const generatedEditDates = { "app/storefront-development/page.mdx": "2024-09-11T10:58:59.290Z", "app/storefront-development/nextjs-starter/page.mdx": "2024-07-04T17:26:03+03:00", "app/basics/page.mdx": "2024-09-03T07:11:06.879Z", - "app/basics/admin-customizations/page.mdx": "2024-09-03T08:07:35.584Z", + "app/basics/admin-customizations/page.mdx": "2024-10-07T12:41:39.218Z", "app/advanced-development/workflows/workflow-timeout/page.mdx": "2024-09-30T08:43:53.131Z", "app/advanced-development/workflows/parallel-steps/page.mdx": "2024-09-30T08:43:53.130Z", "app/advanced-development/page.mdx": "2024-07-04T17:26:03+03:00", @@ -27,7 +27,7 @@ export const generatedEditDates = { "app/advanced-development/modules/container/page.mdx": "2024-09-30T08:43:53.125Z", "app/advanced-development/workflows/execute-another-workflow/page.mdx": "2024-09-30T08:43:53.129Z", "app/basics/loaders/page.mdx": "2024-09-03T08:00:45.993Z", - "app/advanced-development/admin/widgets/page.mdx": "2024-09-30T08:43:53.120Z", + "app/advanced-development/admin/widgets/page.mdx": "2024-10-07T12:51:09.969Z", "app/advanced-development/data-models/page.mdx": "2024-09-19T07:26:43.535Z", "app/advanced-development/modules/remote-link/page.mdx": "2024-09-30T08:43:53.127Z", "app/advanced-development/api-routes/protected-routes/page.mdx": "2024-09-30T08:43:53.121Z", @@ -38,7 +38,7 @@ export const generatedEditDates = { "app/advanced-development/events-and-subscribers/emit-event/page.mdx": "2024-09-30T08:43:53.125Z", "app/advanced-development/workflows/conditions/page.mdx": "2024-09-30T08:43:53.128Z", "app/advanced-development/modules/module-link-directions/page.mdx": "2024-07-24T09:16:01+02:00", - "app/advanced-development/admin/page.mdx": "2024-05-29T13:50:19+03:00", + "app/advanced-development/admin/page.mdx": "2024-10-07T12:39:13.178Z", "app/advanced-development/workflows/long-running-workflow/page.mdx": "2024-09-30T08:43:53.129Z", "app/advanced-development/workflows/constructor-constraints/page.mdx": "2024-10-04T08:40:14.867Z", "app/advanced-development/data-models/write-migration/page.mdx": "2024-07-15T17:46:10+02:00", @@ -54,9 +54,9 @@ export const generatedEditDates = { "app/advanced-development/scheduled-jobs/execution-number/page.mdx": "2024-07-02T09:41:15+00:00", "app/advanced-development/api-routes/parameters/page.mdx": "2024-09-11T10:44:13.491Z", "app/advanced-development/api-routes/http-methods/page.mdx": "2024-09-11T10:43:33.169Z", - "app/advanced-development/admin/tips/page.mdx": "2024-09-10T11:39:51.165Z", + "app/advanced-development/admin/tips/page.mdx": "2024-10-07T12:50:36.335Z", "app/advanced-development/api-routes/cors/page.mdx": "2024-09-30T08:43:53.121Z", - "app/advanced-development/admin/ui-routes/page.mdx": "2024-08-06T09:44:22+02:00", + "app/advanced-development/admin/ui-routes/page.mdx": "2024-10-07T12:52:37.509Z", "app/advanced-development/api-routes/middlewares/page.mdx": "2024-09-11T10:45:31.861Z", "app/advanced-development/modules/isolation/page.mdx": "2024-07-04T17:26:03+03:00", "app/advanced-development/data-models/configure-properties/page.mdx": "2024-09-30T08:43:53.122Z", @@ -96,8 +96,8 @@ export const generatedEditDates = { "app/customization/extend-models/extend-create-product/page.mdx": "2024-09-30T08:43:53.134Z", "app/customization/custom-features/page.mdx": "2024-09-12T11:18:13.271Z", "app/customization/customize-admin/page.mdx": "2024-09-12T12:25:29.853Z", - "app/customization/customize-admin/route/page.mdx": "2024-09-12T12:45:39.258Z", - "app/customization/customize-admin/widget/page.mdx": "2024-09-30T08:43:53.133Z", + "app/customization/customize-admin/route/page.mdx": "2024-10-07T12:43:11.335Z", + "app/customization/customize-admin/widget/page.mdx": "2024-10-07T12:44:24.538Z", "app/customization/extend-models/define-link/page.mdx": "2024-09-30T08:43:53.134Z", "app/customization/extend-models/page.mdx": "2024-09-12T12:38:57.394Z", "app/customization/extend-models/query-linked-records/page.mdx": "2024-09-30T08:43:53.134Z", diff --git a/www/apps/resources/app/admin-components/components/action-menu/page.mdx b/www/apps/resources/app/admin-components/components/action-menu/page.mdx new file mode 100644 index 0000000000..d1dad26c8a --- /dev/null +++ b/www/apps/resources/app/admin-components/components/action-menu/page.mdx @@ -0,0 +1,271 @@ +--- +sidebar_label: "Action Menu" +--- + +import { TypeList } from "docs-ui" + +export const metadata = { + title: `Action Menu - Admin Components`, +} + +# {metadata.title} + +The Medusa Admin often provides additional actions in a dropdown shown when users click a three-dot icon. + +![Example of an action menu in the Medusa Admin](https://res.cloudinary.com/dza7lstvk/image/upload/v1728291319/Medusa%20Resources/action-menu_jnus6k.png) + +To create a component that shows this menu in your customizations, create the file `src/admin/components/action-menu.tsx` with the following content: + +```tsx title="src/admin/components/action-menu.tsx" +import { + DropdownMenu, + IconButton, + clx +} from "@medusajs/ui" +import { EllipsisHorizontal } from "@medusajs/icons" +import { Link } from "react-router-dom" + +export type Action = { + icon: React.ReactNode + label: string + disabled?: boolean +} & ( + | { + to: string + onClick?: never + } + | { + onClick: () => void + to?: never + } +) + +export type ActionGroup = { + actions: Action[] +} + +export type ActionMenuProps = { + groups: ActionGroup[] +} + +export const ActionMenu = ({ groups }: ActionMenuProps) => { + return ( + + + + + + + + {groups.map((group, index) => { + if (!group.actions.length) { + return null + } + + const isLast = index === groups.length - 1 + + return ( + + {group.actions.map((action, index) => { + if (action.onClick) { + return ( + { + e.stopPropagation() + action.onClick() + }} + className={clx( + "[&_svg]:text-ui-fg-subtle flex items-center gap-x-2", + { + "[&_svg]:text-ui-fg-disabled": action.disabled, + } + )} + > + {action.icon} + {action.label} + + ) + } + + return ( +
+ + e.stopPropagation()}> + {action.icon} + {action.label} + + +
+ ) + })} + {!isLast && } +
+ ) + })} +
+
+ ) +} +``` + +The `ActionMenu` component shows a three-dots icon (or `EllipsisHorizontal`) from the [Medusa Icons package](!ui!/icons/overview) in a button. + +When the button is clicked, a dropdown menu is shown with the actions passed in the props. + +The component accepts the following props: + + void`", + optional: true, + description: "The function to execute when the action is clicked. This is required if `to` isn't provided." + } + ] + } + ] + } + ]} +/> + +--- + +## Example + +Use the `ActionMenu` component in any widget or UI route. + +For example, create the widget `src/admin/widgets/product-widget.tsx` with the following content: + +```tsx title="src/admin/widgets/product-widget.tsx" +import { defineWidgetConfig } from "@medusajs/admin-sdk" +import { Pencil } from "@medusajs/icons" +import { Container } from "../components/container" +import { ActionMenu } from "../components/action-menu" + +const ProductWidget = () => { + return ( + + , + label: "Edit", + onClick: () => { + alert("You clicked the edit action!") + } + } + ] + } + ]} /> + + ) +} + +export const config = defineWidgetConfig({ + zone: "product.details.before", +}) + +export default ProductWidget +``` + +This widget also uses a [Container](../container/page.mdx) custom component. + +### Use in Header + +You can also use the action menu in the [Header](../header/page.mdx) component as part of its actions. + +For example: + +```tsx title="src/admin/widgets/product-widget.tsx" +import { defineWidgetConfig } from "@medusajs/admin-sdk" +import { Pencil } from "@medusajs/icons" +import { Container } from "../components/container" +import { Header } from "../components/header" + +const ProductWidget = () => { + return ( + +
, + label: "Edit", + onClick: () => { + alert("You clicked the edit action!") + } + } + ] + } + ] + } + } + ]} + /> + + ) +} + +export const config = defineWidgetConfig({ + zone: "product.details.before", +}) + +export default ProductWidget +``` diff --git a/www/apps/resources/app/admin-components/components/container/page.mdx b/www/apps/resources/app/admin-components/components/container/page.mdx new file mode 100644 index 0000000000..a000513d34 --- /dev/null +++ b/www/apps/resources/app/admin-components/components/container/page.mdx @@ -0,0 +1,65 @@ +--- +sidebar_label: "Container" +--- + +export const metadata = { + title: `Container - Admin Components`, +} + +# {metadata.title} + +The Medusa Admin wraps each section of a page in a container. + +![Example of a container in the Medusa Admin](https://res.cloudinary.com/dza7lstvk/image/upload/v1728287102/Medusa%20Resources/container_soenir.png) + +To create a component that uses the same container styling in your widgets or UI routes, create the file `src/admin/components/container.tsx` with the following content: + +```tsx +import { + Container as UiContainer, + clx +} from "@medusajs/ui" + +type ContainerProps = React.ComponentProps + +export const Container = (props: ContainerProps) => { + return ( + + ) +} +``` + +The `Container` component re-uses the component from the [Medusa UI package](!ui!/components/container) and applies to it classes to match the Medusa Admin's design conventions. + +--- + +## Example + +Use that `Container` component in any widget or UI route. + +For example, create the widget `src/admin/widgets/product-widget.tsx` with the following content: + +```tsx title="src/admin/widgets/product-widget.tsx" +import { defineWidgetConfig } from "@medusajs/admin-sdk" +import { Container } from "../components/container" +import { Header } from "../components/header" + +const ProductWidget = () => { + return ( + +
+ + ) +} + +export const config = defineWidgetConfig({ + zone: "product.details.before", +}) + +export default ProductWidget +``` + +This widget also uses a [Header](../header/page.mdx) custom component. diff --git a/www/apps/resources/app/admin-components/components/forms/page.mdx b/www/apps/resources/app/admin-components/components/forms/page.mdx new file mode 100644 index 0000000000..fc3b34fbd1 --- /dev/null +++ b/www/apps/resources/app/admin-components/components/forms/page.mdx @@ -0,0 +1,584 @@ +--- +sidebar_label: "Forms" +--- + +export const metadata = { + title: `Forms - Admin Components`, +} + +# {metadata.title} + +The Medusa Admin has two types of forms: + +1. Create forms, created using the [FocusModal UI component](!ui!/components/focus-modal). +2. Edit or update forms, created using the [Drawer UI component](!ui!/ui/components/drawer). + +This guide explains how to create these two form types following the Medusa Admin's conventions. + +## Form Tooling + +The Medusa Admin uses the following tools to build the forms: + +1. [react-hook-form](https://react-hook-form.com/) to easily build forms and manage their states. +2. [Zod](https://zod.dev/) to validate the form's fields. + +Both of these libraries are available in your project, so you don't have to install them to use them. + +--- + +## Create Form + +In this section, you'll build a form component to create an item of a resource. + +
+ +```tsx title="src/admin/components/create-form.tsx" +import { + FocusModal, + Heading, + Label, + Input, + Button +} from "@medusajs/ui" +import { + useForm, + FormProvider, + Controller +} from "react-hook-form" +import * as zod from "zod" + +const schema = zod.object({ + name: zod.string() +}) + +export const CreateForm = () => { + const form = useForm>({ + defaultValues: { + name: "" + } + }) + + const handleSubmit = form.handleSubmit(({ name }) => { + // TODO submit to backend + console.log(name) + }) + + return ( + + + + + + +
+ +
+ + + + +
+
+ +
+
+
+ + Create Item + +
+
+ { + return ( +
+
+ +
+ +
+ ) + }} + /> +
+
+
+
+
+
+
+
+ ) +} +``` + +
+ +Unlike other components in this documentation, this form component isn't reusable. You have to create one for every resource that has a create form in the admin. + +Start by creating the file `src/admin/components/create-form.tsx` that you'll create the form in. + +### Create Validation Schema + +In `src/admin/components/create-form.tsx`, create a validation schema with Zod for the form's fields: + +```tsx title="src/admin/components/create-form.tsx" +import * as zod from "zod" + +const schema = zod.object({ + name: zod.string() +}) +``` + +The form in this guide is simple, it only has a required `name` field, which is a string. + +### Initialize Form + +Next, you'll initialize the form using `react-hook-form`. + +Add to `src/admin/components/create-form.tsx` the following: + +```tsx title="src/admin/components/create-form.tsx" +// other imports... +import { useForm } from "react-hook-form" + +// validation schema... + +export const CreateForm = () => { + const form = useForm>({ + defaultValues: { + name: "" + } + }) + + const handleSubmit = form.handleSubmit(({ name }) => { + // TODO submit to backend + console.log(name) + }) + + // TODO render form +} +``` + +You create the `CreateForm` component. For now, it uses `useForm` from `react-hook-form` to initialize a form. + +You also define a `handleSubmit` function to perform an action when the form is submitted. + +You can replace the content of the function with sending a request to Medusa's routes. Refer to [this guide](!docs!/advanced-development/admin/tips#send-requests-to-api-routes) for more details on how to do that. + +### Render Components + +You'll now add a `return` statement that renders the focus modal where the form is shown. + +Replace `// TODO render form` with the following: + +```tsx title="src/admin/components/create-form.tsx" +// other imports... +import { + FocusModal, + Heading, + Label, + Input, + Button +} from "@medusajs/ui" +import { + FormProvider, + Controller +} from "react-hook-form" + +export const CreateForm = () => { + // ... + + return ( + + + + + + +
+ +
+ + + + +
+
+ +
+
+
+ + Create Item + +
+
+ { + return ( +
+
+ +
+ +
+ ) + }} + /> +
+
+
+
+
+
+
+
+ ) +} +``` + +You render a focus modal, with a trigger button to open it. + +In the `FocusModal.Content` component, you wrap the content with the `FormProvider` component from `react-hook-form`, passing it the details of the form you initialized earlier as props. + +In the `FormProvider`, you add a `form` component passing it the `handleSubmit` function you created earlier as the handler of the `onSubmit` event. + +In the `FocusModal.Header` component, you add buttons to save or cancel the form submission. + +Finally, you render the form's components inside the `FocusModal.Body`. To render inputs, you use the `Controller` component imported from `react-hook-form`. + +### Use Create Form Component + +You can use the `CreateForm` component in your widget or UI route. + +For example, create the widget `src/admin/widgets/product-widget.tsx` with the following content: + +```tsx title="src/admin/widgets/product-widget.tsx" +import { defineWidgetConfig } from "@medusajs/admin-sdk" +import { CreateForm } from "../components/create-form" +import { Container } from "../components/container" +import { Header } from "../components/header" + +const ProductWidget = () => { + return ( + +
+ } + ]} + /> + + ) +} + +export const config = defineWidgetConfig({ + zone: "product.details.before", +}) + +export default ProductWidget +``` + +This component uses the [Container](../container/page.mdx) and [Header](../header/page.mdx) custom components. + +It will add at the top of a product's details page a new section, and in its header you'll find a Create button. If you click on it, it will open the focus modal with your form. + +--- + +## Edit Form + +In this section, you'll build a form component to edit an item of a resource. + +
+ +```tsx title="src/admin/components/edit-form.tsx" +import { + Drawer, + Heading, + Label, + Input, + Button +} from "@medusajs/ui" +import { + useForm, + FormProvider, + Controller +} from "react-hook-form" +import * as zod from "zod" + +const schema = zod.object({ + name: zod.string() +}) + +export const EditForm = () => { + const form = useForm>({ + defaultValues: { + name: "" + } + }) + + const handleSubmit = form.handleSubmit(({ name }) => { + // TODO submit to backend + console.log(name) + }) + + return ( + + + + + + +
+ + + Edit Item + + + + { + return ( +
+
+ +
+ +
+ ) + }} + /> +
+ +
+ + + + +
+
+
+
+
+
+ ) +} +``` + +
+ +Unlike other components in this documentation, this form component isn't reusable. You have to create one for every resource that has an edit form in the admin. + +Start by creating the file `src/admin/components/edit-form.tsx` that you'll create the form in. + +### Create Validation Schema + +In `src/admin/components/edit-form.tsx`, create a validation schema with Zod for the form's fields: + +```tsx title="src/admin/components/edit-form.tsx" +import * as zod from "zod" + +const schema = zod.object({ + name: zod.string() +}) +``` + +The form in this guide is simple, it only has a required `name` field, which is a string. + +### Initialize Form + +Next, you'll initialize the form using `react-hook-form`. + +Add to `src/admin/components/edit-form.tsx` the following: + +```tsx title="src/admin/components/edit-form.tsx" +// other imports... +import { useForm } from "react-hook-form" + +// validation schema... + +export const EditForm = () => { + const form = useForm>({ + defaultValues: { + name: "" + } + }) + + const handleSubmit = form.handleSubmit(({ name }) => { + // TODO submit to backend + console.log(name) + }) + + // TODO render form +} +``` + +You create the `EditForm` component. For now, it uses `useForm` from `react-hook-form` to initialize a form. + +You also define a `handleSubmit` function to perform an action when the form is submitted. + +You can replace the content of the function with sending a request to Medusa's routes. Refer to [this guide](!docs!/advanced-development/admin/tips#send-requests-to-api-routes) for more details on how to do that. + +### Render Components + +You'll now add a `return` statement that renders the drawer where the form is shown. + +Replace `// TODO render form` with the following: + +```tsx title="src/admin/components/edit-form.tsx" +// other imports... +import { + Drawer, + Heading, + Label, + Input, + Button +} from "@medusajs/ui" +import { + FormProvider, + Controller +} from "react-hook-form" + +export const EditForm = () => { + // ... + + return ( + + + + + + +
+ + + Edit Item + + + + { + return ( +
+
+ +
+ +
+ ) + }} + /> +
+ +
+ + + + +
+
+
+
+
+
+ ) +} +``` + +You render a drawer, with a trigger button to open it. + +In the `Drawer.Content` component, you wrap the content with the `FormProvider` component from `react-hook-form`, passing it the details of the form you initialized earlier as props. + +In the `FormProvider`, you add a `form` component passing it the `handleSubmit` function you created earlier as the handler of the `onSubmit` event. + +You render the form's components inside the `Drawer.Body`. To render inputs, you use the `Controller` component imported from `react-hook-form`. + +Finally, in the `Drawer.Footer` component, you add buttons to save or cancel the form submission. + +### Use Edit Form Component + +You can use the `EditForm` component in your widget or UI route. + +For example, create the widget `src/admin/widgets/product-widget.tsx` with the following content: + +```tsx title="src/admin/widgets/product-widget.tsx" +import { defineWidgetConfig } from "@medusajs/admin-sdk" +import { Container } from "../components/container" +import { Header } from "../components/header" +import { EditForm } from "../components/edit-form" + +const ProductWidget = () => { + return ( + +
+ } + ]} + /> + + ) +} + +export const config = defineWidgetConfig({ + zone: "product.details.before", +}) + +export default ProductWidget +``` + +This component uses the [Container](../container/page.mdx) and [Header](../header/page.mdx) custom components. + +It will add at the top of a product's details page a new section, and in its header you'll find an "Edit Item" button. If you click on it, it will open the drawer with your form. + diff --git a/www/apps/resources/app/admin-components/components/header/page.mdx b/www/apps/resources/app/admin-components/components/header/page.mdx new file mode 100644 index 0000000000..b5864d6b3e --- /dev/null +++ b/www/apps/resources/app/admin-components/components/header/page.mdx @@ -0,0 +1,191 @@ +--- +sidebar_label: "Header" +--- + +import { TypeList } from "docs-ui" + +export const metadata = { + title: `Header - Admin Components`, +} + +# {metadata.title} + +Each section in the Medusa Admin has a header with a title, and optionally a subtitle with buttons to perform an action. + +![Example of a header in a section](https://res.cloudinary.com/dza7lstvk/image/upload/v1728288562/Medusa%20Resources/header_dtz4gl.png) + +To create a component that uses the same header styling and structure, create the file `src/admin/components/header.tsx` with the following content: + +```tsx title="src/admin/components/header.tsx" +import { Heading, Button, Text } from "@medusajs/ui" +import React from "react" +import { Link, LinkProps } from "react-router-dom" +import { ActionMenu, ActionMenuProps } from "./action-menu" + +export type HeadingProps = { + title: string + subtitle?: string + actions?: ( + { + type: "button", + props: React.ComponentProps + link?: LinkProps + } | + { + type: "action-menu" + props: ActionMenuProps + } | + { + type: "custom" + children: React.ReactNode + } + )[] +} + +export const Header = ({ + title, + subtitle, + actions = [] +}: HeadingProps) => { + return ( +
+
+ {title} + {subtitle && ( + + {subtitle} + + )} +
+ {actions.length > 0 && ( +
+ {actions.map((action, index) => ( + <> + {action.type === "button" && ( + + )} + {action.type === "action-menu" && ( + + )} + {action.type === "custom" && action.children} + + ))} +
+ )} +
+ ) +} +``` + +The `Header` component shows a title, and optionally a subtitle and action buttons. + + + +The component also uses the [Action Menu](../action-menu/page.mdx) custom component. + + + +It accepts the following props: + + + +--- + +## Example + +Use the `Header` component in any widget or UI route. + +For example, create the widget `src/admin/widgets/product-widget.tsx` with the following content: + +```tsx title="src/admin/widgets/product-widget.tsx" +import { defineWidgetConfig } from "@medusajs/admin-sdk" +import { Container } from "../components/container" +import { Header } from "../components/header" + +const ProductWidget = () => { + return ( + +
{ + alert("You clicked the button.") + } + } + } + ]} + /> + + ) +} + +export const config = defineWidgetConfig({ + zone: "product.details.before", +}) + +export default ProductWidget +``` + +This widget also uses a [Container](../container/page.mdx) custom component. diff --git a/www/apps/resources/app/admin-components/components/json-view-section/page.mdx b/www/apps/resources/app/admin-components/components/json-view-section/page.mdx new file mode 100644 index 0000000000..bef5293d72 --- /dev/null +++ b/www/apps/resources/app/admin-components/components/json-view-section/page.mdx @@ -0,0 +1,236 @@ +--- +sidebar_label: "JSON View" +--- + +import { TypeList } from "docs-ui" + +export const metadata = { + title: `JSON View - Admin Components`, +} + +# {metadata.title} + +Detail pages in the Medusa Admin show a JSON section to view the current page's details in JSON format. + +![Example of a JSON section in the admin](https://res.cloudinary.com/dza7lstvk/image/upload/v1728295129/Medusa%20Resources/json_dtbsgm.png) + +To create a component that shows a JSON section in your customizations, create the file `src/admin/components/json-view-section.tsx` with the following content: + +```tsx title="src/admin/components/json-view-section.tsx" +import { + ArrowUpRightOnBox, + Check, + SquareTwoStack, + TriangleDownMini, + XMarkMini, +} from "@medusajs/icons" +import { + Badge, + Container, + Drawer, + Heading, + IconButton, + Kbd, +} from "@medusajs/ui" +import Primitive from "@uiw/react-json-view" +import { CSSProperties, MouseEvent, Suspense, useState } from "react" + +type JsonViewSectionProps = { + data: object + title?: string +} + +export const JsonViewSection = ({ data }: JsonViewSectionProps) => { + const numberOfKeys = Object.keys(data).length + + return ( + +
+ JSON + + {numberOfKeys} keys + +
+ + + + + + + +
+
+ + + + {numberOfKeys} + + + +
+
+ + esc + + + + + + +
+
+ +
+
} + > + + } /> + ( + null + )} + /> + ( + undefined + )} + /> + { + return ( + + {Object.keys(value as object).length} items + + ) + }} + /> + + + + + : + + { + return + }} + /> + + + +
+
+
+
+ ) +} + +type CopiedProps = { + style?: CSSProperties + value: object | undefined +} + +const Copied = ({ style, value }: CopiedProps) => { + const [copied, setCopied] = useState(false) + + const handler = (e: MouseEvent) => { + e.stopPropagation() + setCopied(true) + + if (typeof value === "string") { + navigator.clipboard.writeText(value) + } else { + const json = JSON.stringify(value, null, 2) + navigator.clipboard.writeText(json) + } + + setTimeout(() => { + setCopied(false) + }, 2000) + } + + const styl = { whiteSpace: "nowrap", width: "20px" } + + if (copied) { + return ( + + + + ) + } + + return ( + + + + ) +} +``` + +The `JsonViewSection` component shows a section with the "JSON" title and a button to show the data as JSON in a drawer or side window. + +The `JsonViewSection` accepts a `data` prop, which is the data to show as a JSON object in the drawer. + +--- + +## Example + +Use the `JsonViewSection` component in any widget or UI route. + +For example, create the widget `src/admin/widgets/product-widget.tsx` with the following content: + +```tsx title="src/admin/widgets/product-widget.tsx" +import { defineWidgetConfig } from "@medusajs/admin-sdk" +import { JsonViewSection } from "../components/json-view-section" + +const ProductWidget = () => { + return +} + +export const config = defineWidgetConfig({ + zone: "product.details.before", +}) + +export default ProductWidget +``` + +This shows the JSON section at the top of the product page, passing it the object `{ name: "John" }`. diff --git a/www/apps/resources/app/admin-components/components/section-row/page.mdx b/www/apps/resources/app/admin-components/components/section-row/page.mdx new file mode 100644 index 0000000000..99af5e1ba6 --- /dev/null +++ b/www/apps/resources/app/admin-components/components/section-row/page.mdx @@ -0,0 +1,119 @@ +--- +sidebar_label: "Section Row" +--- + +import { TypeList } from "docs-ui" + +export const metadata = { + title: `Section Row - Admin Components`, +} + +# {metadata.title} + +The Medusa Admin often shows information in rows of label-values, such as when showing a product's details. + +![Example of a section row in the Medusa Admin](https://res.cloudinary.com/dza7lstvk/image/upload/v1728292781/Medusa%20Resources/section-row_kknbnw.png) + +To create a component that shows information in the same structure, create the file `src/admin/components/section-row.tsx` with the following content: + +```tsx title="src/admin/components/section-row.tsx" +import { Text, clx } from "@medusajs/ui" + +export type SectionRowProps = { + title: string + value?: React.ReactNode | string | null + actions?: React.ReactNode +} + +export const SectionRow = ({ title, value, actions }: SectionRowProps) => { + const isValueString = typeof value === "string" || !value + + return ( +
+ + {title} + + + {isValueString ? ( + + {value ?? "-"} + + ) : ( +
{value}
+ )} + + {actions &&
{actions}
} +
+ ) +} +``` + +The `SectionRow` component shows a title and a value in the same row. + +It accepts the following props: + + + +--- + +## Example + +Use the `SectionRow` component in any widget or UI route. + +For example, create the widget `src/admin/widgets/product-widget.tsx` with the following content: + +```tsx title="src/admin/widgets/product-widget.tsx" +import { defineWidgetConfig } from "@medusajs/admin-sdk" +import { Container } from "../components/container" +import { Header } from "../components/header" +import { SectionRow } from "../components/section-row" + +const ProductWidget = () => { + return ( + +
+ + + ) +} + +export const config = defineWidgetConfig({ + zone: "product.details.before", +}) + +export default ProductWidget +``` + +This widget also uses the [Container](../container/page.mdx) and [Header](../header/page.mdx) custom component. diff --git a/www/apps/resources/app/admin-components/components/table/page.mdx b/www/apps/resources/app/admin-components/components/table/page.mdx new file mode 100644 index 0000000000..02087fb9e6 --- /dev/null +++ b/www/apps/resources/app/admin-components/components/table/page.mdx @@ -0,0 +1,245 @@ +--- +sidebar_label: "Table" +--- + +import { TypeList } from "docs-ui" + +export const metadata = { + title: `Table - Admin Components`, +} + +# {metadata.title} + +The listing pages in the Admin show a table with pagination. + +![Example of a table in the product listing page](https://res.cloudinary.com/dza7lstvk/image/upload/v1728295658/Medusa%20Resources/list_ddt9zc.png) + +To create a component that shows a table with pagination, create the file `src/admin/components/table.tsx` with the following content: + +```tsx title="src/admin/components/table.tsx" +import { useMemo } from "react" +import { Table as UiTable } from "@medusajs/ui" + +export type TableProps = { + columns: { + key: string + label?: string + render?: (value: unknown) => React.ReactNode + }[] + data: Record[] + pageSize: number + count: number + currentPage: number + setCurrentPage: (value: number) => void +} + +export const Table = ({ + columns, + data, + pageSize, + count, + currentPage, + setCurrentPage +}: TableProps) => { + const pageCount = useMemo(() => { + return Math.ceil(data.length / pageSize) + }, [data, pageSize]) + + const canNextPage = useMemo(() => { + return currentPage < pageCount - 1 + }, [currentPage, pageCount]) + const canPreviousPage = useMemo(() => { + return currentPage - 1 >= 0 + }, [currentPage]) + + const nextPage = () => { + if (canNextPage) { + setCurrentPage(currentPage + 1) + } + } + + const previousPage = () => { + if (canPreviousPage) { + setCurrentPage(currentPage - 1) + } + } + + return ( +
+ + + + {columns.map((column, index) => ( + + {column.label || column.key} + + ))} + + + + {data.map((item, index) => { + const rowIndex = "id" in item ? item.id as string : index + return ( + + {columns.map((column, index) => ( + + <> + {column.render && column.render(item[column.key])} + {!column.render && ( + <>{item[column.key] as string} + )} + + + ))} + + ) + })} + + + +
+ ) +} +``` + +The `Table` component uses the component from the [UI package](!ui!/components/table), with additional styling and rendering of data. + +It accepts the following props: + + React.ReactNode`", + optional: true, + description: "By default, the data is shown as-is in the table. You can use this function to change how the value is rendered. The function receives the value is a parameter and returns a React node." + } + ] + }, + { + name: "data", + type: "`Record[]`", + optional: false, + description: "The data to show in the table for the current page. The keys of each object should be in the `columns` array." + }, + { + name: "pageSize", + type: "`number`", + optional: false, + description: "The number of items to show per page." + }, + { + name: "count", + type: "`number`", + optional: false, + description: "The total number of items." + }, + { + name: "currentPage", + type: "`number`", + optional: false, + description: "A zero-based index indicating the current page's number." + }, + { + name: "setCurrentPage", + type: "`(value: number) => void`", + optional: false, + description: "A function used to change the current page." + } + ]} +/> + +--- + +## Example + +Use the `Table` component in any widget or UI route. + +For example, create the widget `src/admin/widgets/product-widget.tsx` with the following content: + +```tsx title="src/admin/widgets/product-widget.tsx" +import { defineWidgetConfig } from "@medusajs/admin-sdk" +import { StatusBadge } from "@medusajs/ui" +import { Table } from "../components/table" +import { useState } from "react" +import { Container } from "../components/container" + +const ProductWidget = () => { + const [currentPage, setCurrentPage] = useState(0) + + return ( + + { + const isEnabled = value as boolean + + return ( + + {isEnabled ? "Enabled" : "Disabled"} + + ) + } + } + ]} + data={[ + { + name: "John", + is_enabled: true + }, + { + name: "Jane", + is_enabled: false + } + ]} + pageSize={2} + count={2} + currentPage={currentPage} + setCurrentPage={setCurrentPage} + /> + + ) +} + +export const config = defineWidgetConfig({ + zone: "product.details.before", +}) + +export default ProductWidget +``` + +This widget also uses the [Container](../container.mdx) custom component. diff --git a/www/apps/resources/app/admin-components/layouts/single-column/page.mdx b/www/apps/resources/app/admin-components/layouts/single-column/page.mdx new file mode 100644 index 0000000000..24ed2803fa --- /dev/null +++ b/www/apps/resources/app/admin-components/layouts/single-column/page.mdx @@ -0,0 +1,70 @@ +--- +sidebar_label: "Single Column" +--- + +export const metadata = { + title: `Single Column Layout - Admin Components`, +} + +# {metadata.title} + +The Medusa Admin has pages with a single column of content. + + + +This doesn't include the sidebar, only the main content. + + + +![An example of an admin page with a single column](https://res.cloudinary.com/dza7lstvk/image/upload/v1728286605/Medusa%20Resources/single-column.png) + +To create a layout that you can use in UI routes to support one column of content, create the component `src/admin/layouts/single-column.tsx` with the following content: + +```tsx title="src/admin/layouts/single-column.tsx" +export type SingleColumnLayoutProps = { + children: React.ReactNode +} + +export const SingleColumnLayout = ({ children }: SingleColumnLayoutProps) => { + return ( +
+ {children} +
+ ) +} +``` + +The `SingleColumnLayout` accepts the content in the `children` props. + +--- + +## Example + +Use the `SingleColumnLayout` component in your UI routes that have a single column. For example: + +```tsx title="src/admin/routes/custom/page.tsx" highlights={[["9"]]} +import { defineRouteConfig } from "@medusajs/admin-sdk" +import { ChatBubbleLeftRight } from "@medusajs/icons" +import { Container } from "../../components/container" +import { SingleColumnLayout } from "../../layouts/single-column" +import { Header } from "../../components/header" + +const CustomPage = () => { + return ( + + +
+ + + ) +} + +export const config = defineRouteConfig({ + label: "Custom", + icon: ChatBubbleLeftRight, +}) + +export default CustomPage +``` + +This UI route also uses a [Container](../../components/container/page.mdx) and a [Header]() custom components. \ No newline at end of file diff --git a/www/apps/resources/app/admin-components/layouts/two-column/page.mdx b/www/apps/resources/app/admin-components/layouts/two-column/page.mdx new file mode 100644 index 0000000000..dffcc0e68c --- /dev/null +++ b/www/apps/resources/app/admin-components/layouts/two-column/page.mdx @@ -0,0 +1,89 @@ +--- +sidebar_label: "Two Column" +--- + +export const metadata = { + title: `Two Column Layout - Admin Components`, +} + +# {metadata.title} + +The Medusa Admin has pages with two columns of content. + + + +This doesn't include the sidebar, only the main content. + + + +![An example of an admin page with two columns](https://res.cloudinary.com/dza7lstvk/image/upload/v1728286690/Medusa%20Resources/two-column_sdnkg0.png) + +To create a layout that you can use in UI routes to support two columns of content, create the component `src/admin/layouts/two-column.tsx` with the following content: + +```tsx title="src/admin/layouts/two-column.tsx" +export type TwoColumnLayoutProps = { + firstCol: React.ReactNode + secondCol: React.ReactNode +} + +export const TwoColumnLayout = ({ + firstCol, + secondCol +}: TwoColumnLayoutProps) => { + return ( +
+
+ {firstCol} +
+
+ {secondCol} +
+
+ ) +} +``` + +The `TwoColumnLayout` accepts two props: + +- `firstCol` indicating the content of the first column. +- `secondCol` indicating the content of the second column. + +--- + +## Example + +Use the `TwoColumnLayout` component in your UI routes that have a single column. For example: + +```tsx title="src/admin/routes/custom/page.tsx" highlights={[["9"]]} +import { defineRouteConfig } from "@medusajs/admin-sdk" +import { ChatBubbleLeftRight } from "@medusajs/icons" +import { Container } from "../../components/container" +import { Header } from "../../components/header" +import { TwoColumnLayout } from "../../layouts/two-column" + +const CustomPage = () => { + return ( + +
+ + } + secondCol={ + +
+ + } + /> + ) +} + +export const config = defineRouteConfig({ + label: "Custom", + icon: ChatBubbleLeftRight, +}) + +export default CustomPage +``` + +This UI route also uses [Container](../../components/container/page.mdx) and [Header]() custom components. \ No newline at end of file diff --git a/www/apps/resources/app/admin-components/page.mdx b/www/apps/resources/app/admin-components/page.mdx new file mode 100644 index 0000000000..57f0abde07 --- /dev/null +++ b/www/apps/resources/app/admin-components/page.mdx @@ -0,0 +1,27 @@ +import { ChildDocs } from "docs-ui" + +export const metadata = { + title: `Admin Components`, +} + +# {metadata.title} + +In this section, you'll find examples of implementing common Medusa Admin components and layouts. + +These components are useful to follow the same design conventions as the Medusa Admin, and are build on top of the [Medusa UI package](!ui!). + +Refer to the [Medusa UI documentation](!ui!) for a full list of components. + +## Layouts + +Use these components to set the layout of your UI route. + + + +--- + +## Components + +Use these components in your widgets and UI routes. + + diff --git a/www/apps/resources/generated/edit-dates.mjs b/www/apps/resources/generated/edit-dates.mjs index daccbe7c8b..3b80b77aa1 100644 --- a/www/apps/resources/generated/edit-dates.mjs +++ b/www/apps/resources/generated/edit-dates.mjs @@ -2218,6 +2218,16 @@ export const generatedEditDates = { "references/user/interfaces/user.IModuleService/page.mdx": "2024-10-03T00:12:20.657Z", "references/user/interfaces/user.MessageAggregatorFormat/page.mdx": "2024-10-03T00:12:20.662Z", "app/troubleshooting/dist-imports/page.mdx": "2024-10-03T09:19:37.639Z", + "app/admin-components/components/action-menu/page.mdx": "2024-10-07T11:16:26.178Z", + "app/admin-components/components/container/page.mdx": "2024-10-07T11:15:58.824Z", + "app/admin-components/components/header/page.mdx": "2024-10-07T11:16:47.407Z", + "app/admin-components/components/json-view-section/page.mdx": "2024-10-07T11:15:58.833Z", + "app/admin-components/components/section-row/page.mdx": "2024-10-07T11:15:58.832Z", + "app/admin-components/components/table/page.mdx": "2024-10-07T11:15:58.833Z", + "app/admin-components/page.mdx": "2024-10-07T11:09:49.493Z", + "app/admin-components/layouts/single-column/page.mdx": "2024-10-07T11:16:06.435Z", + "app/admin-components/layouts/two-column/page.mdx": "2024-10-07T11:16:10.092Z", + "app/admin-components/components/forms/page.mdx": "2024-10-09T12:48:04.229Z", "app/commerce-modules/auth/reset-password/page.mdx": "2024-10-08T07:34:08.488Z", "app/storefront-development/customers/reset-password/page.mdx": "2024-09-25T10:21:46.647Z", "app/commerce-modules/api-key/links-to-other-modules/page.mdx": "2024-10-08T08:05:36.596Z", diff --git a/www/apps/resources/generated/files-map.mjs b/www/apps/resources/generated/files-map.mjs index 47d9901a5c..12cdc91054 100644 --- a/www/apps/resources/generated/files-map.mjs +++ b/www/apps/resources/generated/files-map.mjs @@ -1,4 +1,44 @@ export const filesMap = [ + { + "filePath": "/www/apps/resources/app/admin-components/components/action-menu/page.mdx", + "pathname": "/admin-components/components/action-menu" + }, + { + "filePath": "/www/apps/resources/app/admin-components/components/container/page.mdx", + "pathname": "/admin-components/components/container" + }, + { + "filePath": "/www/apps/resources/app/admin-components/components/forms/page.mdx", + "pathname": "/admin-components/components/forms" + }, + { + "filePath": "/www/apps/resources/app/admin-components/components/header/page.mdx", + "pathname": "/admin-components/components/header" + }, + { + "filePath": "/www/apps/resources/app/admin-components/components/json-view-section/page.mdx", + "pathname": "/admin-components/components/json-view-section" + }, + { + "filePath": "/www/apps/resources/app/admin-components/components/section-row/page.mdx", + "pathname": "/admin-components/components/section-row" + }, + { + "filePath": "/www/apps/resources/app/admin-components/components/table/page.mdx", + "pathname": "/admin-components/components/table" + }, + { + "filePath": "/www/apps/resources/app/admin-components/layouts/single-column/page.mdx", + "pathname": "/admin-components/layouts/single-column" + }, + { + "filePath": "/www/apps/resources/app/admin-components/layouts/two-column/page.mdx", + "pathname": "/admin-components/layouts/two-column" + }, + { + "filePath": "/www/apps/resources/app/admin-components/page.mdx", + "pathname": "/admin-components" + }, { "filePath": "/www/apps/resources/app/admin-widget-injection-zones/page.mdx", "pathname": "/admin-widget-injection-zones" diff --git a/www/apps/resources/generated/sidebar.mjs b/www/apps/resources/generated/sidebar.mjs index adbda2d6ff..0bc291600f 100644 --- a/www/apps/resources/generated/sidebar.mjs +++ b/www/apps/resources/generated/sidebar.mjs @@ -7725,128 +7725,6 @@ export const generatedSidebar = [ } ] }, - { - "type": "separator" - }, - { - "loaded": true, - "isPathHref": true, - "type": "category", - "title": "SDKs and Tools", - "children": [ - { - "loaded": true, - "isPathHref": true, - "type": "link", - "path": "/create-medusa-app", - "title": "create-medusa-app", - "children": [] - }, - { - "loaded": true, - "isPathHref": true, - "type": "link", - "path": "/medusa-cli", - "title": "Medusa CLI", - "isChildSidebar": true, - "childSidebarTitle": "Medusa CLI Reference", - "children": [ - { - "loaded": true, - "isPathHref": true, - "type": "link", - "path": "/medusa-cli", - "title": "Overview", - "children": [] - }, - { - "type": "separator" - }, - { - "loaded": true, - "isPathHref": true, - "type": "category", - "title": "Commands", - "autogenerate_path": "medusa-cli/commands", - "children": [ - { - "loaded": true, - "isPathHref": true, - "type": "link", - "path": "/medusa-cli/commands/new", - "title": "new", - "children": [] - }, - { - "loaded": true, - "isPathHref": true, - "type": "link", - "path": "/medusa-cli/commands/develop", - "title": "develop", - "children": [] - }, - { - "loaded": true, - "isPathHref": true, - "type": "link", - "path": "/medusa-cli/commands/start", - "title": "start", - "children": [] - }, - { - "loaded": true, - "isPathHref": true, - "type": "link", - "path": "/medusa-cli/commands/user", - "title": "user", - "children": [] - }, - { - "loaded": true, - "isPathHref": true, - "type": "link", - "path": "/medusa-cli/commands/db", - "title": "db", - "children": [] - }, - { - "loaded": true, - "isPathHref": true, - "type": "link", - "path": "/medusa-cli/commands/exec", - "title": "exec", - "children": [] - }, - { - "loaded": true, - "isPathHref": true, - "type": "link", - "path": "/medusa-cli/commands/start-cluster", - "title": "start-cluster", - "children": [] - }, - { - "loaded": true, - "isPathHref": true, - "type": "link", - "path": "/medusa-cli/commands/telemtry", - "title": "telemetry", - "children": [] - } - ] - } - ] - }, - { - "loaded": true, - "isPathHref": true, - "type": "link", - "path": "/nextjs-starter", - "title": "Next.js Starter", - "children": [] - } - ] - }, { "loaded": true, "isPathHref": true, @@ -8089,6 +7967,128 @@ export const generatedSidebar = [ } ] }, + { + "type": "separator" + }, + { + "loaded": true, + "isPathHref": true, + "type": "category", + "title": "SDKs and Tools", + "children": [ + { + "loaded": true, + "isPathHref": true, + "type": "link", + "path": "/create-medusa-app", + "title": "create-medusa-app", + "children": [] + }, + { + "loaded": true, + "isPathHref": true, + "type": "link", + "path": "/medusa-cli", + "title": "Medusa CLI", + "isChildSidebar": true, + "childSidebarTitle": "Medusa CLI Reference", + "children": [ + { + "loaded": true, + "isPathHref": true, + "type": "link", + "path": "/medusa-cli", + "title": "Overview", + "children": [] + }, + { + "type": "separator" + }, + { + "loaded": true, + "isPathHref": true, + "type": "category", + "title": "Commands", + "autogenerate_path": "medusa-cli/commands", + "children": [ + { + "loaded": true, + "isPathHref": true, + "type": "link", + "path": "/medusa-cli/commands/new", + "title": "new", + "children": [] + }, + { + "loaded": true, + "isPathHref": true, + "type": "link", + "path": "/medusa-cli/commands/develop", + "title": "develop", + "children": [] + }, + { + "loaded": true, + "isPathHref": true, + "type": "link", + "path": "/medusa-cli/commands/start", + "title": "start", + "children": [] + }, + { + "loaded": true, + "isPathHref": true, + "type": "link", + "path": "/medusa-cli/commands/user", + "title": "user", + "children": [] + }, + { + "loaded": true, + "isPathHref": true, + "type": "link", + "path": "/medusa-cli/commands/db", + "title": "db", + "children": [] + }, + { + "loaded": true, + "isPathHref": true, + "type": "link", + "path": "/medusa-cli/commands/exec", + "title": "exec", + "children": [] + }, + { + "loaded": true, + "isPathHref": true, + "type": "link", + "path": "/medusa-cli/commands/start-cluster", + "title": "start-cluster", + "children": [] + }, + { + "loaded": true, + "isPathHref": true, + "type": "link", + "path": "/medusa-cli/commands/telemtry", + "title": "telemetry", + "children": [] + } + ] + } + ] + }, + { + "loaded": true, + "isPathHref": true, + "type": "link", + "path": "/nextjs-starter", + "title": "Next.js Starter", + "children": [] + } + ] + }, { "loaded": true, "isPathHref": true, @@ -8523,14 +8523,6 @@ export const generatedSidebar = [ } ] }, - { - "loaded": true, - "isPathHref": true, - "type": "link", - "path": "/references/medusa-config", - "title": "Medusa Configurations", - "children": [] - }, { "type": "separator" }, @@ -8540,6 +8532,14 @@ export const generatedSidebar = [ "type": "category", "title": "General", "children": [ + { + "loaded": true, + "isPathHref": true, + "type": "link", + "path": "/references/medusa-config", + "title": "Medusa Configurations", + "children": [] + }, { "loaded": true, "isPathHref": true, @@ -8758,6 +8758,125 @@ export const generatedSidebar = [ } ] }, + { + "type": "separator" + }, + { + "loaded": true, + "isPathHref": true, + "type": "category", + "title": "Admin", + "children": [ + { + "loaded": true, + "isPathHref": true, + "type": "link", + "path": "/admin-widget-injection-zones", + "title": "Admin Widget Injection Zones", + "children": [] + }, + { + "loaded": true, + "isPathHref": true, + "type": "link", + "path": "/admin-components", + "title": "Admin Components", + "isChildSidebar": true, + "children": [ + { + "loaded": true, + "isPathHref": true, + "type": "category", + "title": "Layouts", + "autogenerate_path": "/admin-components/layouts", + "children": [ + { + "loaded": true, + "isPathHref": true, + "type": "link", + "path": "/admin-components/layouts/single-column", + "title": "Single Column", + "children": [] + }, + { + "loaded": true, + "isPathHref": true, + "type": "link", + "path": "/admin-components/layouts/two-column", + "title": "Two Column", + "children": [] + } + ] + }, + { + "loaded": true, + "isPathHref": true, + "type": "category", + "title": "Components", + "autogenerate_path": "/admin-components/components", + "children": [ + { + "loaded": true, + "isPathHref": true, + "type": "link", + "path": "/admin-components/components/action-menu", + "title": "Action Menu", + "children": [] + }, + { + "loaded": true, + "isPathHref": true, + "type": "link", + "path": "/admin-components/components/container", + "title": "Container", + "children": [] + }, + { + "loaded": true, + "isPathHref": true, + "type": "link", + "path": "/admin-components/components/forms", + "title": "Forms", + "children": [] + }, + { + "loaded": true, + "isPathHref": true, + "type": "link", + "path": "/admin-components/components/header", + "title": "Header", + "children": [] + }, + { + "loaded": true, + "isPathHref": true, + "type": "link", + "path": "/admin-components/components/json-view-section", + "title": "JSON View", + "children": [] + }, + { + "loaded": true, + "isPathHref": true, + "type": "link", + "path": "/admin-components/components/section-row", + "title": "Section Row", + "children": [] + }, + { + "loaded": true, + "isPathHref": true, + "type": "link", + "path": "/admin-components/components/table", + "title": "Table", + "children": [] + } + ] + } + ] + } + ] + }, { "loaded": true, "isPathHref": true, @@ -8779,14 +8898,6 @@ export const generatedSidebar = [ "path": "/events-reference", "title": "Events List", "children": [] - }, - { - "loaded": true, - "isPathHref": true, - "type": "link", - "path": "/admin-widget-injection-zones", - "title": "Admin Widget Injection Zones", - "children": [] } ] }, diff --git a/www/apps/resources/sidebar.mjs b/www/apps/resources/sidebar.mjs index 908fade290..deb78983ed 100644 --- a/www/apps/resources/sidebar.mjs +++ b/www/apps/resources/sidebar.mjs @@ -1596,47 +1596,6 @@ export const sidebar = sidebarAttachHrefCommonOptions([ }, ], }, - { - type: "separator", - }, - { - type: "category", - title: "SDKs and Tools", - children: [ - { - type: "link", - path: "/create-medusa-app", - title: "create-medusa-app", - }, - { - type: "link", - path: "/medusa-cli", - title: "Medusa CLI", - isChildSidebar: true, - childSidebarTitle: "Medusa CLI Reference", - children: [ - { - type: "link", - path: "/medusa-cli", - title: "Overview", - }, - { - type: "separator", - }, - { - type: "category", - title: "Commands", - autogenerate_path: "medusa-cli/commands", - }, - ], - }, - { - type: "link", - path: "/nextjs-starter", - title: "Next.js Starter", - }, - ], - }, { type: "link", path: "/architectural-modules", @@ -1799,6 +1758,47 @@ export const sidebar = sidebarAttachHrefCommonOptions([ }, ], }, + { + type: "separator", + }, + { + type: "category", + title: "SDKs and Tools", + children: [ + { + type: "link", + path: "/create-medusa-app", + title: "create-medusa-app", + }, + { + type: "link", + path: "/medusa-cli", + title: "Medusa CLI", + isChildSidebar: true, + childSidebarTitle: "Medusa CLI Reference", + children: [ + { + type: "link", + path: "/medusa-cli", + title: "Overview", + }, + { + type: "separator", + }, + { + type: "category", + title: "Commands", + autogenerate_path: "medusa-cli/commands", + }, + ], + }, + { + type: "link", + path: "/nextjs-starter", + title: "Next.js Starter", + }, + ], + }, { type: "link", path: "/storefront-development", @@ -2067,11 +2067,6 @@ export const sidebar = sidebarAttachHrefCommonOptions([ }, ], }, - { - type: "link", - path: "/references/medusa-config", - title: "Medusa Configurations", - }, { type: "separator", }, @@ -2079,6 +2074,11 @@ export const sidebar = sidebarAttachHrefCommonOptions([ type: "category", title: "General", children: [ + { + type: "link", + path: "/references/medusa-config", + title: "Medusa Configurations", + }, { type: "link", path: "/upgrade-guides", @@ -2209,6 +2209,38 @@ export const sidebar = sidebarAttachHrefCommonOptions([ }, ], }, + { + type: "separator", + }, + { + type: "category", + title: "Admin", + children: [ + { + type: "link", + path: "/admin-widget-injection-zones", + title: "Admin Widget Injection Zones", + }, + { + type: "link", + path: "/admin-components", + title: "Admin Components", + isChildSidebar: true, + children: [ + { + type: "category", + title: "Layouts", + autogenerate_path: "/admin-components/layouts", + }, + { + type: "category", + title: "Components", + autogenerate_path: "/admin-components/components", + }, + ], + }, + ], + }, { type: "category", title: "Lists", @@ -2223,11 +2255,6 @@ export const sidebar = sidebarAttachHrefCommonOptions([ path: "/events-reference", title: "Events List", }, - { - type: "link", - path: "/admin-widget-injection-zones", - title: "Admin Widget Injection Zones", - }, ], }, {