docs: updates to admin customization docs (#7493)
* updated admin docs * re-add navigation and parameters sections * update injection zones * update cli scripts docs * added list of injection zones * add details about widget props * restructure admin injection zones
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -4,19 +4,12 @@ export const metadata = {
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
<Note type="soon">
|
||||
|
||||
Admin customizations are coming soon.
|
||||
|
||||
</Note>
|
||||
|
||||
In the next chapters, you'll learn more about possible admin customizations.
|
||||
|
||||
You can customize the admin dashboard by:
|
||||
|
||||
- Adding new sections to existing pages using Widgets.
|
||||
- Adding new pages using UI Routes.
|
||||
- Adding new pages to the Settings section of the admin dashboard using Setting Pages.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,152 +0,0 @@
|
||||
export const metadata = {
|
||||
title: `${pageNumber} Admin Setting Pages`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
<Note type="soon">
|
||||
|
||||
Admin customizations are coming soon.
|
||||
|
||||
</Note>
|
||||
|
||||
In this chapter, you’ll learn how to create a setting page in the admin dashboard.
|
||||
|
||||
## What is a Setting Page?
|
||||
|
||||
A setting page is a React component that adds a new page to the settings panel of the admin dashboard.
|
||||
|
||||
For example, you may create a setting page to manage configurations related to your custom functionalities.
|
||||
|
||||
---
|
||||
|
||||
## How to Create a Setting Page?
|
||||
|
||||
A setting page is created in a file named `page.tsx` under the `src/admin/settings` directory. The file’s default export must be the React component, and it must also export a configuration object.
|
||||
|
||||
For example, you can create the file `src/admin/settings/custom/page.tsx` with the following content:
|
||||
|
||||
```tsx title="src/admin/settings/custom/page.tsx"
|
||||
import type { SettingConfig } from "@medusajs/admin"
|
||||
import { ChatBubbleLeftRight } from "@medusajs/icons"
|
||||
|
||||
const CustomSettingPage = () => {
|
||||
return (
|
||||
<div>
|
||||
<h1>Custom Setting Page</h1>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const config: SettingConfig = {
|
||||
card: {
|
||||
label: "Custom",
|
||||
description: "Manage your custom settings",
|
||||
// optional
|
||||
icon: ChatBubbleLeftRight,
|
||||
},
|
||||
}
|
||||
|
||||
export default CustomSettingPage
|
||||
```
|
||||
|
||||
The new setting page’s path is the file’s path relative to `src/admin/settings` and prefixed with `/a/settings`. So, the above UI route is a new page added at the path `localhost:7001/a/settings/custom`.
|
||||
|
||||
The setting page is shown on the Settings panel as a card. In the exported configuration object, you configure the card’s label, description, and optionally icon. In this example, you use an icon from [Medusa’s UI Icons package](https://docs.medusajs.com/ui/icons/overview).
|
||||
|
||||
### Test the Setting Page
|
||||
|
||||
To test the setting page, start the Medusa application:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Then, open the Settings page of the admin dashboard. You’ll find a new card that links to your setting page.
|
||||
|
||||
---
|
||||
|
||||
## Using UI Components
|
||||
|
||||
Similar to other admin customizations, it’s highly recommended that you use the [Medusa UI package](https://docs.medusajs.com/ui) to match your page’s design with the rest of the Medusa Admin.
|
||||
|
||||
For example, you can rewrite the above UI route to the following:
|
||||
|
||||
```tsx title="src/admin/settings/custom/page.tsx"
|
||||
import type { SettingConfig } from "@medusajs/admin"
|
||||
import { ChatBubbleLeftRight } from "@medusajs/icons"
|
||||
import { Container, Heading } from "@medusajs/ui"
|
||||
|
||||
const CustomSettingPage = () => {
|
||||
return (
|
||||
<Container>
|
||||
<Heading level="h1">Custom Setting Page</Heading>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export const config: SettingConfig = {
|
||||
card: {
|
||||
label: "Custom",
|
||||
description: "Manage your custom settings",
|
||||
icon: ChatBubbleLeftRight,
|
||||
},
|
||||
}
|
||||
|
||||
export default CustomSettingPage
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Setting Page Props
|
||||
|
||||
A setting page receives a `notify` prop, which is an object having the following properties:
|
||||
|
||||
- `success`: a function that shows a success toast message.
|
||||
- `error`: a function that shows an error toast message.
|
||||
- `warn`: a function that shows a warning toast message.
|
||||
- `info`: a function that shows an info toast message.
|
||||
|
||||
Each of these functions accepts two parameters: the message’s title and the message’s content.
|
||||
|
||||
For example:
|
||||
|
||||
```tsx title="src/admin/settings/custom/page.tsx" highlights={[["11", "success", "Show a success toast message on the click of a button."]]}
|
||||
import type { RouteProps, SettingConfig } from "@medusajs/admin"
|
||||
import { ChatBubbleLeftRight } from "@medusajs/icons"
|
||||
import { Container, Heading, Button } from "@medusajs/ui"
|
||||
|
||||
const CustomSettingPage = ({ notify }: RouteProps) => {
|
||||
return (
|
||||
<Container>
|
||||
<Heading level="h1">Custom Setting Page</Heading>
|
||||
<Button
|
||||
onClick={() =>
|
||||
notify.success("Success!", "You clicked the button!")
|
||||
}
|
||||
className="mt-3"
|
||||
>
|
||||
Click me
|
||||
</Button>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export const config: SettingConfig = {
|
||||
card: {
|
||||
label: "Custom",
|
||||
description: "Manage your custom settings",
|
||||
icon: ChatBubbleLeftRight,
|
||||
},
|
||||
}
|
||||
|
||||
export default CustomSettingPage
|
||||
```
|
||||
|
||||
If you click the button on your setting page, a toast message will show with the title and message you specified.
|
||||
|
||||
<Note title="Tip">
|
||||
|
||||
Admin UI Routes support [Tailwind CSS](https://tailwindcss.com/) out of the box.
|
||||
|
||||
</Note>
|
||||
@@ -4,22 +4,8 @@ export const metadata = {
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
<Note type="soon">
|
||||
|
||||
Admin customizations are coming soon.
|
||||
|
||||
</Note>
|
||||
|
||||
In this chapter, you'll find some tips for your admin development.
|
||||
|
||||
## Sending Requests to API Routes
|
||||
|
||||
To send requests to your API routes in your admin customizations, it’s highly recommended to use the Medusa React or Medusa JS Client packages.
|
||||
|
||||
Check out their references for more details on available hooks or methods and how to use them.
|
||||
|
||||
---
|
||||
|
||||
## Routing Functionalities
|
||||
|
||||
To navigate or link to other pages, or use other routing functionalities, use the [react-router-dom](https://reactrouter.com/en/main) package:
|
||||
@@ -30,40 +16,34 @@ npm install react-router-dom
|
||||
|
||||
For example:
|
||||
|
||||
```tsx title="src/admin/widgets/product-widget.tsx" highlights={[["18", "Link", "Add a link to another page."]]}
|
||||
import type {
|
||||
WidgetConfig,
|
||||
ProductDetailsWidgetProps,
|
||||
} from "@medusajs/admin"
|
||||
import { Container, Heading, Button } from "@medusajs/ui"
|
||||
export const highlights = [
|
||||
["9", "Link", "Add a link to another page"],
|
||||
["9", '"/orders', "Add the path without the `/app` prefix."]
|
||||
]
|
||||
|
||||
```tsx title="src/admin/widgets/product-widget.tsx" highlights={highlights}
|
||||
import { defineWidgetConfig } from "@medusajs/admin-shared"
|
||||
import { Container } from "@medusajs/ui"
|
||||
import { Link } from "react-router-dom"
|
||||
|
||||
// The widget
|
||||
const ProductWidget = ({
|
||||
product,
|
||||
}: ProductDetailsWidgetProps) => {
|
||||
const ProductWidget = () => {
|
||||
return (
|
||||
<Container>
|
||||
<Heading level="h2">
|
||||
Product Widget {product.title}
|
||||
</Heading>
|
||||
<Button className="mt-3" variant="transparent">
|
||||
<Link to={"/a/orders"}>View Orders</Link>
|
||||
</Button>
|
||||
<Link to={"/orders"}>View Orders</Link>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
// The widget's configurations
|
||||
export const config: WidgetConfig = {
|
||||
export const config = defineWidgetConfig({
|
||||
zone: "product.details.after",
|
||||
}
|
||||
})
|
||||
|
||||
export default ProductWidget
|
||||
|
||||
```
|
||||
|
||||
This adds a widget in a product's details page with a link to the Orders page.
|
||||
This adds a widget in a product's details page with a link to the Orders page. The link's path must be without the `/app` prefix.
|
||||
|
||||
<Note title="Learn more">
|
||||
|
||||
|
||||
@@ -4,17 +4,11 @@ export const metadata = {
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
<Note type="soon">
|
||||
|
||||
Admin customizations are coming soon.
|
||||
|
||||
</Note>
|
||||
|
||||
In this chapter, you’ll learn how to create a UI route in the admin dashboard.
|
||||
|
||||
## What is a UI Route?
|
||||
|
||||
A UI route is a React Component that adds a custom new page to your admin dashboard. The UI Route can be shown in the sidebar or added as a nested page.
|
||||
A UI route is a React Component that adds a new page to your admin dashboard. The UI Route can be shown in the sidebar or added as a nested page.
|
||||
|
||||
For example, you may add a new page to manage product reviews.
|
||||
|
||||
@@ -34,7 +28,7 @@ const CustomPage = () => {
|
||||
export default CustomPage
|
||||
```
|
||||
|
||||
The new page’s path is the file’s path relative to `src/admin/routes` and prefixed with `/a`. So, the above UI route is a new page added at the path `localhost:7001/a/custom`.
|
||||
The new page’s path is the file’s path relative to `src/admin/routes`. So, the above UI route is a new page added at the path `localhost:9000/app/custom`.
|
||||
|
||||
### Test the UI Route
|
||||
|
||||
@@ -44,7 +38,43 @@ To test the UI route, start the Medusa application:
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Then, after logging into the admin dashboard, open the page `localhost:7001/a/custom` to see your custom page.
|
||||
Then, after logging into the admin dashboard, open the page `localhost:9000/app/custom` to see your custom page.
|
||||
|
||||
---
|
||||
|
||||
## Show UI Route in the Sidebar
|
||||
|
||||
A UI route file can export a configuration object that indicates a new item must be added in the sidebar linking to the new UI route.
|
||||
|
||||
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."]
|
||||
]
|
||||
|
||||
```tsx title="src/admin/routes/custom/page.tsx" highlights={[["21"], ["22"], ["23"], ["24"], ["25"], ["26"]]}
|
||||
import { defineRouteConfig } from "@medusajs/admin-shared";
|
||||
import { ChatBubbleLeftRight } from "@medusajs/icons"
|
||||
|
||||
const CustomPage = () => {
|
||||
return <div>This is my custom route</div>
|
||||
}
|
||||
|
||||
export const config = defineRouteConfig({
|
||||
label: "Custom Route",
|
||||
icon: ChatBubbleLeftRight,
|
||||
})
|
||||
|
||||
export default CustomPage
|
||||
```
|
||||
|
||||
The configuration object is creaetd by the `defineRouteConfig` function imported from `@medusajs/admin-shared`. It accepts the following properties:
|
||||
|
||||
- `label`: the new sidebar item’s label.
|
||||
- `icon`: an optional React component that acts as an icon in the sidebar.
|
||||
|
||||
The above example adds a new sidebar item with the label `Custom Route` and an icon from the [Medusa UI Icons package](!ui!/icons/overview).
|
||||
|
||||
---
|
||||
|
||||
@@ -55,104 +85,50 @@ Similar to Widgets, it’s highly recommended that you use the [Medusa UI packag
|
||||
For example, you can rewrite the above UI route to the following:
|
||||
|
||||
```tsx title="src/admin/routes/custom/page.tsx"
|
||||
import { defineRouteConfig } from "@medusajs/admin-shared"
|
||||
import { ChatBubbleLeftRight } from "@medusajs/icons"
|
||||
import { Container } from "@medusajs/ui"
|
||||
|
||||
const CustomPage = () => {
|
||||
return <Container>This is my custom route</Container>
|
||||
}
|
||||
|
||||
export const config = defineRouteConfig({
|
||||
label: "Custom Route",
|
||||
icon: ChatBubbleLeftRight,
|
||||
})
|
||||
|
||||
export default CustomPage
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## UI Route Props
|
||||
## Create Settings Page
|
||||
|
||||
A UI Route receives a `notify` prop, which is an object having the following properties:
|
||||
|
||||
- `success`: a function that shows a success toast message.
|
||||
- `error`: a function that shows an error toast message.
|
||||
- `warn`: a function that shows a warning toast message.
|
||||
- `info`: a function that shows an info toast message.
|
||||
|
||||
Each of these functions accepts two parameters: the message’s title and the message’s content.
|
||||
To create a page under the settings section of the admin dashboard, create the UI route file under the path `src/admin/routes/settings`.
|
||||
|
||||
For example:
|
||||
|
||||
```tsx title="src/admin/routes/custom/page.tsx" highlights={[["10", "success", "Show a success toast message on the click of a button."]]}
|
||||
import { RouteProps } from "@medusajs/admin"
|
||||
import { Container, Text, Button } from "@medusajs/ui"
|
||||
```tsx title="src/admin/routes/settings/custom/page.tsx"
|
||||
import { defineRouteConfig } from "@medusajs/admin-shared"
|
||||
import { Container, Heading } from "@medusajs/ui"
|
||||
|
||||
const CustomPage = ({ notify }: RouteProps) => {
|
||||
const CustomSettingPage = () => {
|
||||
return (
|
||||
<Container>
|
||||
<Text>This is my custom route</Text>
|
||||
<Button
|
||||
onClick={() =>
|
||||
notify.success("Success!", "You clicked the button!")
|
||||
}
|
||||
className="mt-3"
|
||||
>
|
||||
Click me
|
||||
</Button>
|
||||
<Heading level="h1">Custom Setting Page</Heading>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export default CustomPage
|
||||
export const config = defineRouteConfig({
|
||||
label: "Custom",
|
||||
})
|
||||
|
||||
export default CustomSettingPage;
|
||||
```
|
||||
|
||||
<Note title="Tip">
|
||||
|
||||
Admin UI Routes support [Tailwind CSS](https://tailwindcss.com/) out of the box.
|
||||
|
||||
</Note>
|
||||
|
||||
---
|
||||
|
||||
## Show UI Route in the Sidebar
|
||||
|
||||
A UI route file can export a configuration object that indicates a new item must be added in the sidebar linking to the new UI route.
|
||||
|
||||
The configuration object has the property `link`, which is an object having the following properties:
|
||||
|
||||
- `label`: the new sidebar item’s label.
|
||||
- `icon`: an optional React component that acts as an icon in the sidebar. If not provided, a default icon is used.
|
||||
|
||||
For example:
|
||||
|
||||
```tsx title="src/admin/routes/custom/page.tsx" highlights={[["21"], ["22"], ["23"], ["24"], ["25"], ["26"]]}
|
||||
import { RouteConfig, RouteProps } from "@medusajs/admin"
|
||||
import { Container, Text, Button } from "@medusajs/ui"
|
||||
import { ChatBubbleLeftRight } from "@medusajs/icons"
|
||||
|
||||
const CustomPage = ({ notify }: RouteProps) => {
|
||||
return (
|
||||
<Container>
|
||||
<Text>This is my custom route</Text>
|
||||
<Button
|
||||
onClick={() =>
|
||||
notify.success("Success!", "You clicked the button!")
|
||||
}
|
||||
className="mt-3"
|
||||
>
|
||||
Click me
|
||||
</Button>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export const config: RouteConfig = {
|
||||
link: {
|
||||
label: "Custom Route",
|
||||
icon: ChatBubbleLeftRight,
|
||||
},
|
||||
}
|
||||
|
||||
export default CustomPage
|
||||
```
|
||||
|
||||
This adds a new sidebar item with the label `Custom Route` and an icon from the [Medusa UI Icons package](https://docs.medusajs.com/ui/icons/overview).
|
||||
This adds a page under the path `/app/settings/custom`. An item is also added to the settings sidebar with the label `Custom`.
|
||||
|
||||
---
|
||||
|
||||
@@ -179,4 +155,6 @@ const CustomPage = () => {
|
||||
}
|
||||
|
||||
export default CustomPage
|
||||
```
|
||||
```
|
||||
|
||||
If you run the Medusa application and go to `localhost:9000/app/custom/123`, you'll see `123` printed in the page.
|
||||
|
||||
@@ -6,12 +6,6 @@ export const metadata = {
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
<Note type="soon">
|
||||
|
||||
Admin customizations are coming soon.
|
||||
|
||||
</Note>
|
||||
|
||||
In this chapter, you’ll learn more about widgets and how to use them.
|
||||
|
||||
## What is an Admin Widget?
|
||||
@@ -28,8 +22,13 @@ A widget is created in a file under the `src/admin/widgets` directory. The file
|
||||
|
||||
For example, create the file `src/admin/widgets/product-widget.tsx` with the following content:
|
||||
|
||||
```tsx title="src/admin/widgets/product-widget.tsx" highlights={[["4", "ProductWidget", "The React component of the product widget."], ["14", "", "The zone to inject the widget to."]]}
|
||||
import type { WidgetConfig } from "@medusajs/admin"
|
||||
export const widgetHighlights = [
|
||||
["4", "ProductWidget", "The React component of the product widget."],
|
||||
["14", "zone", "The zone to inject the widget to."]
|
||||
]
|
||||
|
||||
```tsx title="src/admin/widgets/product-widget.tsx" highlights={widgetHighlights}
|
||||
import { defineWidgetConfig } from "@medusajs/admin-shared"
|
||||
|
||||
// The widget
|
||||
const ProductWidget = () => {
|
||||
@@ -41,16 +40,20 @@ const ProductWidget = () => {
|
||||
}
|
||||
|
||||
// The widget's configurations
|
||||
export const config: WidgetConfig = {
|
||||
export const config = defineWidgetConfig({
|
||||
zone: "product.details.after",
|
||||
}
|
||||
})
|
||||
|
||||
export default ProductWidget
|
||||
```
|
||||
|
||||
The widget only shows the heading `Product Widget`.
|
||||
|
||||
In the exported widget’s configurations, you must specify the zone to inject the widget into. The `zone` property can be a string or an array of strings, each being the name of the injection zone.
|
||||
Use the `defineWidgetConfig` function imported from `@medusajs/admin-shared` to create and export the widget's configurations.
|
||||
|
||||
The function accepts as a parameter an object with the following property:
|
||||
|
||||
- `zone`: A string or an array of strings, each being the name of the zone to inject the widget into.
|
||||
|
||||
In the example above, the widget is injected after a product’s details.
|
||||
|
||||
@@ -66,6 +69,37 @@ Then, open a product’s details page. You’ll find your custom widget at the b
|
||||
|
||||
---
|
||||
|
||||
## Detail Widget Props
|
||||
|
||||
Widgets that are injected into a details page (for example, `product.details.after`) receive a `data` prop, which is the main data of the details page (for example, the product object).
|
||||
|
||||
For example:
|
||||
|
||||
```tsx title="src/admin/widgets/product-widget.tsx" highlights={[["5"]]}
|
||||
import { defineWidgetConfig } from "@medusajs/admin-shared"
|
||||
import { DetailWidgetProps, AdminProduct } from "@medusajs/types"
|
||||
|
||||
const ProductWidget = ({
|
||||
data
|
||||
}: DetailWidgetProps<AdminProduct>) => {
|
||||
return (
|
||||
<div>
|
||||
<h2>Product Widget {data.title}</h2>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const config = defineWidgetConfig({
|
||||
zone: "product.details.after",
|
||||
})
|
||||
|
||||
export default ProductWidget
|
||||
```
|
||||
|
||||
Notice that the type of the props is `DetailWidgetProps`, which accepts as a type argument the expected type of the data.
|
||||
|
||||
---
|
||||
|
||||
## Using UI Components
|
||||
|
||||
It’s highly recommended that you use the [Medusa UI package](https://docs.medusajs.com/ui) to match your widget’s design with the rest of the Medusa Admin.
|
||||
@@ -73,7 +107,7 @@ It’s highly recommended that you use the [Medusa UI package](https://docs.medu
|
||||
For example, you can rewrite the above component to the following:
|
||||
|
||||
```tsx title="src/admin/widgets/product-widget.tsx"
|
||||
import type { WidgetConfig } from "@medusajs/admin"
|
||||
import { defineWidgetConfig } from "@medusajs/admin-shared"
|
||||
import { Container, Heading } from "@medusajs/ui"
|
||||
|
||||
const ProductWidget = () => {
|
||||
@@ -84,72 +118,16 @@ const ProductWidget = () => {
|
||||
)
|
||||
}
|
||||
|
||||
export const config: WidgetConfig = {
|
||||
export const config: WidgetConfig = defineWidgetConfig({
|
||||
zone: "product.details.after",
|
||||
}
|
||||
})
|
||||
|
||||
export default ProductWidget
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Widget Props
|
||||
|
||||
A widget receives a `notify` prop, which is an object having the following properties:
|
||||
|
||||
- `success`: a function that shows a success toast message.
|
||||
- `error`: a function that shows an error toast message.
|
||||
- `warn`: a function that shows a warning toast message.
|
||||
- `info`: a function that shows an info toast message.
|
||||
|
||||
Each of these functions accepts two parameters: the message’s title, and the message’s content.
|
||||
|
||||
In addition, some injection zones provide additional props based on the page’s context.
|
||||
|
||||
For example, you can rewrite the above widget to the following:
|
||||
|
||||
```tsx title="src/admin/widgets/product-widget.tsx" highlights={[["14", "product.title", "Show the product's title."], ["18", "success", "Show a success toast message on the click of a button."]]}
|
||||
import type {
|
||||
WidgetConfig,
|
||||
ProductDetailsWidgetProps,
|
||||
} from "@medusajs/admin"
|
||||
import { Container, Heading, Button } from "@medusajs/ui"
|
||||
|
||||
const ProductWidget = ({
|
||||
notify,
|
||||
product,
|
||||
}: ProductDetailsWidgetProps) => {
|
||||
return (
|
||||
<Container>
|
||||
<Heading level="h2">
|
||||
Product Widget {product.title}
|
||||
</Heading>
|
||||
<Button
|
||||
onClick={() =>
|
||||
notify.success("Success!", "You clicked the button!")
|
||||
}
|
||||
className="mt-3"
|
||||
>
|
||||
Click me
|
||||
</Button>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export const config: WidgetConfig = {
|
||||
zone: "product.details.after",
|
||||
}
|
||||
|
||||
export default ProductWidget
|
||||
```
|
||||
|
||||
Since the widget is in the product’s details page, it receives the product as a prop. The widget now shows the title of the product in the header.
|
||||
|
||||
It also shows a button that, when you click, shows a success toast message.
|
||||
|
||||
<Note title="Tip">
|
||||
|
||||
Admin Widgets support [Tailwind CSS](https://tailwindcss.com/) out of the box.
|
||||
Admin Widgets also support [Tailwind CSS](https://tailwindcss.com/) out of the box.
|
||||
|
||||
</Note>
|
||||
|
||||
|
||||
@@ -43,15 +43,12 @@ The function receives as a parameter an object having a `container` property, wh
|
||||
|
||||
## How to Run Custom CLI Script?
|
||||
|
||||
To run the custom CLI script, `build` your code then run the `exec` command:
|
||||
To run the custom CLI script, run the Medusa CLI's `exec` command:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run build
|
||||
npx medusa exec ./dist/scripts/my-script.js
|
||||
npx medusa exec ./src/scripts/my-script.ts
|
||||
```
|
||||
|
||||
Notice that you pass the path to the file in the `dist` directory.
|
||||
|
||||
---
|
||||
|
||||
## Custom CLI Script Arguments
|
||||
@@ -73,6 +70,5 @@ export default async function myScript ({
|
||||
Then, pass the arguments in the `exec` command after the file path:
|
||||
|
||||
```bash npm2yarn
|
||||
npm run build
|
||||
npx medusa exec ./dist/scripts/my-script.js arg1 arg2
|
||||
```
|
||||
npx medusa exec ./src/scripts/my-script.ts arg1 arg2
|
||||
```
|
||||
|
||||
@@ -6,19 +6,13 @@ export const metadata = {
|
||||
|
||||
In this chapter, you’ll learn how to customize the Medusa Admin dashboard.
|
||||
|
||||
<Note type="soon">
|
||||
|
||||
Admin customizations are coming soon.
|
||||
|
||||
</Note>
|
||||
|
||||
## Overview
|
||||
|
||||
The Medusa Admin is an admin dashboard that merchants use to manage their store's data.
|
||||
|
||||
You can extend the Medusa Admin to add widgets and new pages. Your customizations interact with API routes to provide merchants with custom functionalities.
|
||||
|
||||
The Medusa Admin is installed in your Medusa application and runs at port `7001` when you start the Medusa application.
|
||||
The Medusa Admin is installed in your Medusa application and runs at the path `/app` when you start the Medusa application.
|
||||
|
||||
---
|
||||
|
||||
@@ -29,7 +23,7 @@ A widget is a React component that can be injected into an existing page in the
|
||||
For example, create the file `src/admin/widgets/product-widget.tsx` with the following content:
|
||||
|
||||
```tsx title="src/admin/widgets/product-widget.tsx"
|
||||
import type { WidgetConfig } from "@medusajs/admin"
|
||||
import { defineWidgetConfig } from "@medusajs/admin-shared"
|
||||
|
||||
const ProductWidget = () => {
|
||||
return (
|
||||
@@ -39,9 +33,9 @@ const ProductWidget = () => {
|
||||
)
|
||||
}
|
||||
|
||||
export const config: WidgetConfig = {
|
||||
export const config = defineWidgetConfig({
|
||||
zone: "product.details.after",
|
||||
}
|
||||
})
|
||||
|
||||
export default ProductWidget
|
||||
```
|
||||
|
||||
@@ -216,18 +216,10 @@ export const sidebar = sidebarAttachHrefCommonOptions(
|
||||
path: "/advanced-development/admin/ui-routes",
|
||||
title: "Admin UI Routes",
|
||||
},
|
||||
{
|
||||
path: "/advanced-development/admin/setting-pages",
|
||||
title: "Admin Setting Pages",
|
||||
},
|
||||
{
|
||||
path: "/advanced-development/admin/tips",
|
||||
title: "Tips",
|
||||
},
|
||||
{
|
||||
path: "/advanced-development/admin/onboarding-example",
|
||||
title: "Example: Onboarding Widget",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,400 +0,0 @@
|
||||
import { Table, TypeList } from "docs-ui"
|
||||
|
||||
export const metadata = {
|
||||
title: `Medusa Admin Configurations`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
You can configure the Medusa Admin plugin to change its PORT, the Medusa server's URL, and more. You can also extend the Webpack configurations.
|
||||
|
||||
## Plugin Options
|
||||
|
||||
The plugin accepts the following options:
|
||||
|
||||
```js title="medusa-config.js"
|
||||
const plugins = [
|
||||
// ...
|
||||
{
|
||||
resolve: "@medusajs/admin",
|
||||
/** @type {import('@medusajs/admin').PluginOptions} */
|
||||
options: {
|
||||
serve: true,
|
||||
autoRebuild: true,
|
||||
backend: "https://example.com",
|
||||
path: "/app",
|
||||
outDir: "build",
|
||||
develop: {
|
||||
open: true,
|
||||
port: 7001,
|
||||
logLevel: "error",
|
||||
stats: "normal",
|
||||
allowedHosts: "auto",
|
||||
webSocketURL: undefined,
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
<TypeList types={[
|
||||
{
|
||||
name: "serve",
|
||||
type: "boolean",
|
||||
optional: true,
|
||||
defaultValue: "true",
|
||||
description: "Whether to serve the admin dashboard when the Medusa backend starts. If set to `false`, you can serve the admin dashboard using the [dev command](#develop-command-options).",
|
||||
expandable: false,
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: "autoRebuild",
|
||||
type: "boolean",
|
||||
optional: true,
|
||||
defaultValue: "false",
|
||||
description: "Whether the admin UI should be rebuilt if there are any changes or if a missing build is detected when the backend starts. If not set, you must [manually build the admin dashboard](#build-command-options).",
|
||||
expandable: false,
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: "backend",
|
||||
type: "string",
|
||||
optional: true,
|
||||
defaultValue: "",
|
||||
description: "The URL of the Medusa backend. Its value is only used if the `serve` option is set to `false`.",
|
||||
expandable: false,
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: "path",
|
||||
type: "string",
|
||||
optional: true,
|
||||
defaultValue: "/app",
|
||||
description: "The path the admin server should run on when running the Medusa backend in production. It must be prefixed with a slash `/`, but it can't end with a `/`, which throws an error. It also can't be one of the reserved paths: \"admin\" and \"store\".",
|
||||
expandable: false,
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: "outDir",
|
||||
type: "string",
|
||||
optional: true,
|
||||
defaultValue: "",
|
||||
description: "The directory to output the admin build to. By default, the plugin builds the admin to the `build` directory in the root of the Medusa backend directory.",
|
||||
expandable: false,
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: "develop",
|
||||
type: "object",
|
||||
optional: true,
|
||||
defaultValue: "",
|
||||
description: "Options for the admin development server.",
|
||||
expandable: false,
|
||||
children: [
|
||||
{
|
||||
name: "open",
|
||||
type: "boolean",
|
||||
optional: true,
|
||||
defaultValue: "true",
|
||||
description: "Whether the browser should be opened when the admin development server starts.",
|
||||
expandable: false,
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: "port",
|
||||
type: "number",
|
||||
optional: true,
|
||||
defaultValue: "7001",
|
||||
description: "The port the admin dashboard runs on.",
|
||||
expandable: false,
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: "logLevel",
|
||||
type: "\"error\" \\| \"none\" \\| \"warn\" \\| \"info\" \\| \"log\" \\| \"verbose\"",
|
||||
optional: true,
|
||||
defaultValue: "error",
|
||||
description: "The log level of the admin development server.",
|
||||
expandable: false,
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: "stats",
|
||||
type: "\"normal\" \\| \"debug\"",
|
||||
optional: true,
|
||||
defaultValue: "normal",
|
||||
description: "The verbosity of the admin development server.",
|
||||
expandable: false,
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: "allowedHosts",
|
||||
type: "\"auto\" \\| \"all\" \\| string[]",
|
||||
optional: true,
|
||||
defaultValue: "auto",
|
||||
description: "The development server's allowed hosts.",
|
||||
expandable: false,
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: "webSocketURL",
|
||||
type: "string \\| object \\| undefined",
|
||||
optional: true,
|
||||
defaultValue: "",
|
||||
description: "The URL to a web socket server",
|
||||
expandable: false,
|
||||
children: [
|
||||
{
|
||||
name: "hostname",
|
||||
type: "string",
|
||||
optional: true,
|
||||
defaultValue: "",
|
||||
description: "The web socket's hostname.",
|
||||
expandable: false,
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: "password",
|
||||
type: "string",
|
||||
optional: true,
|
||||
defaultValue: "",
|
||||
description: "The web socket's password.",
|
||||
expandable: false,
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: "path name",
|
||||
type: "string",
|
||||
optional: true,
|
||||
defaultValue: "",
|
||||
description: "The web socket's path name.",
|
||||
expandable: false,
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: "port",
|
||||
type: "string",
|
||||
optional: true,
|
||||
defaultValue: "",
|
||||
description: "The web socket's port.",
|
||||
expandable: false,
|
||||
children: []
|
||||
},
|
||||
{
|
||||
name: "username",
|
||||
type: "string",
|
||||
optional: true,
|
||||
defaultValue: "",
|
||||
description: "The web socket's username.",
|
||||
expandable: false,
|
||||
children: []
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
]} sectionTitle="Plugin Options" />
|
||||
|
||||
---
|
||||
|
||||
## Admin CLI Commands
|
||||
|
||||
The `medusa-admin` CLI tool is installed in your Medusa application. It's used within the `package.json`'s scripts to build admin assets.
|
||||
|
||||
### build
|
||||
|
||||
The `build` command in the admin CLI allows you to manually build the admin dashboard. For example:
|
||||
|
||||
```json title="package.json"
|
||||
{
|
||||
"scripts": {
|
||||
// other scripts...
|
||||
"build:admin": "medusa-admin build"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Options
|
||||
|
||||
<Table>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell>Option</Table.HeaderCell>
|
||||
<Table.HeaderCell>Description</Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
|
||||
`--deployment`
|
||||
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
|
||||
Build admin assets for deployment. When this option is added, plugin options are not loaded from `medusa-config.js` anymore, and
|
||||
the backend URL is loaded from the `MEDUSA_ADMIN_BACKEND_URL` environment variable.
|
||||
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
</Table.Body>
|
||||
</Table>
|
||||
|
||||
### develop
|
||||
|
||||
The `develop` command in the admin CLI allows you to run the admin dashboard in development separately from the Medusa application. For example:
|
||||
|
||||
```json title="package.json"
|
||||
{
|
||||
"scripts": {
|
||||
// other scripts...
|
||||
"dev:admin": "medusa-admin develop"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Options
|
||||
|
||||
<Table>
|
||||
<Table.Header>
|
||||
<Table.Row>
|
||||
<Table.HeaderCell>Option</Table.HeaderCell>
|
||||
<Table.HeaderCell>Description</Table.HeaderCell>
|
||||
<Table.HeaderCell>Default</Table.HeaderCell>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
|
||||
`--backend <url>`, `-b <url>`
|
||||
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
|
||||
The URL of the Medusa backend.
|
||||
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
|
||||
The value of the environment variable `MEDUSA_ADMIN_BACKEND_URL`
|
||||
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
|
||||
`--port <url>`, `-p <url>`
|
||||
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
|
||||
The port to run the admin on.
|
||||
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
|
||||
`7001`
|
||||
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
</Table.Body>
|
||||
</Table>
|
||||
|
||||
## Change the Medusa Application URL
|
||||
|
||||
### In Development
|
||||
|
||||
To change the Medusa application's URL that the admin sends request to, disable the `serve` plugin option and set the `backend` option to the new URL.
|
||||
|
||||
However, this requires you to also set-up the [develop command](#develop-command-options) as the admin will no longer start with the Medusa application.
|
||||
|
||||
For example:
|
||||
|
||||
```js title="medusa-config.js"
|
||||
const plugins = [
|
||||
// ...
|
||||
{
|
||||
resolve: "@medusajs/admin",
|
||||
/** @type {import('@medusajs/admin').PluginOptions} */
|
||||
options: {
|
||||
serve: false,
|
||||
backend: "http://localhost:9001",
|
||||
// other options...
|
||||
},
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
### In Production
|
||||
|
||||
<Note>
|
||||
|
||||
This assumes that you've deployed the admin separately and you're passing the `--deployment` option to the [build command](#build-command-options).
|
||||
|
||||
</Note>
|
||||
|
||||
To change the backend's URL that the admin sends request to, set the environment variable `MEDUSA_ADMIN_BACKEND_URL` to the backend's URL.
|
||||
|
||||
For example:
|
||||
|
||||
```bash
|
||||
MEDUSA_ADMIN_BACKEND_URL=https://example.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Custom Environment Variables
|
||||
|
||||
To set environment variables that you want to access in your admin dashboard's customizations (such as in [widgets](!docs!/advanced-development/admin/widgets) or [UI routes](!docs!/advanced-development/admin/ui-routes)), your environment variables must be prefixed with `MEDUSA_ADMIN_`. Otherwise, it won't be loaded within the admin.
|
||||
|
||||
For example:
|
||||
|
||||
```bash
|
||||
MEDUSA_ADMIN_CUSTOM_API_KEY=123...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Custom Webpack Configurations
|
||||
|
||||
<Note type="warning">
|
||||
|
||||
This is an advanced feature and requires knowledge of configuring webpack. If configured wrongly, it may lead to the admin application breaking.
|
||||
|
||||
</Note>
|
||||
|
||||
<Note>
|
||||
|
||||
Plugins can't include webpack customizations.
|
||||
|
||||
</Note>
|
||||
|
||||
The Medusa Admin uses [Webpack](https://webpack.js.org/) to define the configurations for both the Medusa Admin plugin and your customizations.
|
||||
|
||||
You can extend the default webpack configurations defined in the admin plugin to add your custom configurations, such as to support styling your extensions with CSS Modules.
|
||||
|
||||
To do that, create the file `src/admin/webpack.config.js` that uses the `withCustomWebpackConfig` method imported from `@medusajs/admin` to export the extended configurations:
|
||||
|
||||
```js title="src/admin/webpack.config.js"
|
||||
import { withCustomWebpackConfig } from "@medusajs/admin"
|
||||
|
||||
export default withCustomWebpackConfig((config, webpack) => {
|
||||
config.plugins.push(
|
||||
new webpack.DefinePlugin({
|
||||
"process.env": {
|
||||
NODE_ENV: JSON.stringify("production"),
|
||||
API_URL:
|
||||
JSON.stringify("https://api.medusa-commerce.com"),
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
return config
|
||||
})
|
||||
```
|
||||
|
||||
The method `withCustomWebpackConfig` accepts a callback function that must return an object of [webpack configuration](https://webpack.js.org/configuration/). The callback function accepts two parameters:
|
||||
|
||||
1. The first parameter is an object that holds the default webpack configuration. Add your configurations to this object, then return it. Not returning the default configurations breaks the application.
|
||||
2. The second parameter is the webpack instance.
|
||||
@@ -588,7 +588,7 @@ npx medusa exec [file] [args...]
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
|
||||
The path to a JavaScript file holding the function to execute.
|
||||
The path to the TypeScript or JavaScript file holding the function to execute.
|
||||
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
export const metadata = {
|
||||
title: `Signing in to Medusa Admin`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
If you've created a new Medusa backend and used the `seed` command, the default credentials are:
|
||||
|
||||
```bash noReport
|
||||
email: admin@medusa-test.com
|
||||
password: supersecret
|
||||
```
|
||||
|
||||
Alternatively, you can create your own users using the Medusa CLI tool:
|
||||
|
||||
```bash
|
||||
npx medusa user -e some@email.com -p somepassword
|
||||
```
|
||||
@@ -1,93 +0,0 @@
|
||||
export const metadata = {
|
||||
title: `Admin Webpack Build Error`,
|
||||
}
|
||||
|
||||
# {metadata.title}
|
||||
|
||||
If you run the `build` command in your backend and you get an error message during the admin build process similar to the following:
|
||||
|
||||
```bash noReport noCopy
|
||||
The left-hand side of an assignment expression must be a variable or a property access.
|
||||
```
|
||||
|
||||
Make sure that in your admin customizations (widget, UI route, or settings page) you're not using a type imported from `@medusajs/medusa`.
|
||||
|
||||
This is often the case if you're using a type or an enum necessary for a request sent with the JS Client or Medusa React library.
|
||||
|
||||
For example:
|
||||
|
||||
```ts
|
||||
import {
|
||||
Region,
|
||||
ShippingOptionPriceType,
|
||||
} from "@medusajs/medusa"
|
||||
import type Medusa from "@medusajs/medusa-js"
|
||||
|
||||
export default async function prepareShippingOptions(
|
||||
client: Medusa,
|
||||
region: Region
|
||||
) {
|
||||
let {
|
||||
shipping_options,
|
||||
} = await client.admin.shippingOptions.list({
|
||||
region_id: region.id,
|
||||
})
|
||||
if (!shipping_options.length) {
|
||||
shipping_options = [(
|
||||
await client.admin.shippingOptions.create({
|
||||
"name": "PostFake Standard",
|
||||
"region_id": region.id,
|
||||
"provider_id": "manual",
|
||||
"data": {
|
||||
"id": "manual-fulfillment",
|
||||
},
|
||||
// THIS CAUSES THE ERROR
|
||||
"price_type": ShippingOptionPriceType.FLAT_RATE,
|
||||
"amount": 1000,
|
||||
}
|
||||
)).shipping_option]
|
||||
}
|
||||
|
||||
return shipping_options
|
||||
}
|
||||
```
|
||||
|
||||
In this case, you're using the `ShippingOptionPriceType` type to send a request with the JS Client.
|
||||
|
||||
Instead, change it to the string value. If you get a TypeScript error, you can add `// @ts-ignore` before the line:
|
||||
|
||||
```ts
|
||||
import {
|
||||
Region,
|
||||
ShippingOptionPriceType,
|
||||
} from "@medusajs/medusa"
|
||||
import type Medusa from "@medusajs/medusa-js"
|
||||
|
||||
export default async function prepareShippingOptions(
|
||||
client: Medusa,
|
||||
region: Region
|
||||
) {
|
||||
let {
|
||||
shipping_options,
|
||||
} = await client.admin.shippingOptions.list({
|
||||
region_id: region.id,
|
||||
})
|
||||
if (!shipping_options.length) {
|
||||
shipping_options = [(
|
||||
await client.admin.shippingOptions.create({
|
||||
"name": "PostFake Standard",
|
||||
"region_id": region.id,
|
||||
"provider_id": "manual",
|
||||
"data": {
|
||||
"id": "manual-fulfillment",
|
||||
},
|
||||
// @ts-expect-error can't use type from core
|
||||
"price_type": "flat_rate",
|
||||
"amount": 1000,
|
||||
}
|
||||
)).shipping_option]
|
||||
}
|
||||
|
||||
return shipping_options
|
||||
}
|
||||
```
|
||||
@@ -1668,10 +1668,6 @@ export const sidebar = sidebarAttachHrefCommonOptions([
|
||||
path: "/references/medusa-config",
|
||||
title: "Medusa Application",
|
||||
},
|
||||
// {
|
||||
// path: "/configurations/medusa-admin",
|
||||
// title: "Medusa Admin",
|
||||
// },
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -1800,20 +1796,6 @@ export const sidebar = sidebarAttachHrefCommonOptions([
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: "Medusa Admin",
|
||||
hasTitleStyling: true,
|
||||
children: [
|
||||
{
|
||||
path: "/troubleshooting/admin-sign-in",
|
||||
title: "Signing In",
|
||||
},
|
||||
{
|
||||
path: "/troubleshooting/admin-custom-hooks-error",
|
||||
title: "Custom Hooks Error",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user