docs: add copy subscriber button (#12405)
* docs: add copy subscriber button * re-generate * fixes + update copy button
This commit is contained in:
+67
-51
@@ -3,18 +3,23 @@
|
||||
import {
|
||||
Badge,
|
||||
DetailsSummary,
|
||||
DropdownMenu,
|
||||
Link,
|
||||
MarkdownContent,
|
||||
parseEventPayload,
|
||||
Tabs,
|
||||
TabsContent,
|
||||
TabsContentWrapper,
|
||||
TabsList,
|
||||
TabsTrigger,
|
||||
Tooltip,
|
||||
useCopy,
|
||||
useGenerateSnippet,
|
||||
} from "docs-ui"
|
||||
import { useMemo } from "react"
|
||||
import type { OpenAPI } from "types"
|
||||
import TagOperationParameters from "../../Parameters"
|
||||
import { Brackets, CheckCircle, SquareTwoStack, Tag } from "@medusajs/icons"
|
||||
|
||||
export type TagsOperationDescriptionSectionEventsProps = {
|
||||
events: OpenAPI.OasEvents[]
|
||||
@@ -68,62 +73,73 @@ const TagsOperationDescriptionSectionEvent = ({
|
||||
}: {
|
||||
event: OpenAPI.OasEvents
|
||||
}) => {
|
||||
const parsedPayload: OpenAPI.SchemaObject = useMemo(() => {
|
||||
const payloadParams = event.payload.matchAll(
|
||||
/([\w_]+),? \/\/ (\(\w*\) )*(.*)/g
|
||||
)
|
||||
const payload = Array.from(payloadParams).map((match) => {
|
||||
return {
|
||||
name: match[1],
|
||||
type: match[2]?.replace(/\(|\)/g, "") || "string",
|
||||
description: match[3],
|
||||
}
|
||||
})
|
||||
return {
|
||||
type: "object",
|
||||
required: ["payload"],
|
||||
properties: {
|
||||
payload: {
|
||||
type: "object",
|
||||
description: "The payload emitted with the event",
|
||||
required: [...payload.map((param) => param.name)],
|
||||
properties: payload.reduce(
|
||||
(acc, curr) => {
|
||||
acc[curr.name] = {
|
||||
type: curr.type as OpenAPI.OpenAPIV3.NonArraySchemaObjectType,
|
||||
description: curr.description,
|
||||
properties: {},
|
||||
}
|
||||
return acc
|
||||
},
|
||||
{} as Record<string, OpenAPI.SchemaObject>
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
const {
|
||||
parsed_payload: parsedPayload,
|
||||
payload_for_snippet: payloadForSnippet,
|
||||
} = useMemo(() => {
|
||||
return parseEventPayload(event.payload)
|
||||
}, [event.payload])
|
||||
const { snippet } = useGenerateSnippet({
|
||||
type: "subscriber",
|
||||
options: {
|
||||
event: event.name,
|
||||
payload: payloadForSnippet,
|
||||
},
|
||||
})
|
||||
const { handleCopy: handleEventNameCopy, isCopied: eventNameCopied } =
|
||||
useCopy(event.name)
|
||||
const { handleCopy: handleSnippetCopy, isCopied: snippetCopied } =
|
||||
useCopy(snippet)
|
||||
return (
|
||||
<TabsContent value={event.name}>
|
||||
<div className="my-1 flex flex-wrap gap-1">
|
||||
<MarkdownContent
|
||||
allowedElements={["code", "p", "a"]}
|
||||
className={"[&_p:last-child]:!mb-1"}
|
||||
>
|
||||
{`\`${event.name}\`: ${event.description}`}
|
||||
</MarkdownContent>
|
||||
{event.deprecated &&
|
||||
(event.deprecated_message ? (
|
||||
<Tooltip text={event.deprecated_message}>
|
||||
<div className="my-1 flex flex-wrap justify-between items-center mb-1">
|
||||
<div className="flex flex-wrap items-center gap-0.5">
|
||||
<MarkdownContent
|
||||
allowedElements={["code", "p", "a"]}
|
||||
className={"[&_p:last-child]:!mb-0"}
|
||||
>
|
||||
{event.description}
|
||||
</MarkdownContent>
|
||||
{event.deprecated &&
|
||||
(event.deprecated_message ? (
|
||||
<Tooltip text={event.deprecated_message}>
|
||||
<Badge variant="orange">Deprecated</Badge>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<Badge variant="orange">Deprecated</Badge>
|
||||
))}
|
||||
{event.version && (
|
||||
<Tooltip text={`This event is emitted since v${event.version}`}>
|
||||
<Badge variant="blue">v{event.version}</Badge>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<Badge variant="orange">Deprecated</Badge>
|
||||
))}
|
||||
{event.version && (
|
||||
<Tooltip text={`This event is emitted since v${event.version}`}>
|
||||
<Badge variant="blue">v{event.version}</Badge>
|
||||
</Tooltip>
|
||||
)}
|
||||
)}
|
||||
</div>
|
||||
<DropdownMenu
|
||||
dropdownButtonContent={
|
||||
<>
|
||||
{eventNameCopied || snippetCopied ? (
|
||||
<CheckCircle />
|
||||
) : (
|
||||
<SquareTwoStack />
|
||||
)}
|
||||
</>
|
||||
}
|
||||
menuItems={[
|
||||
{
|
||||
type: "action",
|
||||
title: "Copy event name",
|
||||
action: () => handleEventNameCopy(),
|
||||
icon: <Tag />,
|
||||
},
|
||||
{
|
||||
type: "action",
|
||||
title: "Copy subscriber for event",
|
||||
action: () => handleSnippetCopy(),
|
||||
icon: <Brackets />,
|
||||
},
|
||||
]}
|
||||
menuClassName="z-10"
|
||||
/>
|
||||
</div>
|
||||
<TagOperationParameters
|
||||
schemaObject={parsedPayload}
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
"dependencies": {
|
||||
"@mdx-js/loader": "^3.1.0",
|
||||
"@mdx-js/react": "^3.1.0",
|
||||
"@medusajs/icons": "2.6.0",
|
||||
"@medusajs/ui": "4.0.6",
|
||||
"@medusajs/icons": "2.7.1",
|
||||
"@medusajs/ui": "4.0.9",
|
||||
"@next/mdx": "15.3.1",
|
||||
"@react-hook/resize-observer": "^2.0.2",
|
||||
"@readme/openapi-parser": "^2.5.0",
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
"dependencies": {
|
||||
"@mdx-js/loader": "^3.1.0",
|
||||
"@mdx-js/react": "^3.1.0",
|
||||
"@medusajs/icons": "~2.5.1",
|
||||
"@medusajs/icons": "~2.7.1",
|
||||
"@next/mdx": "15.3.1",
|
||||
"clsx": "^2.1.0",
|
||||
"docs-ui": "*",
|
||||
|
||||
+19406
-18107
File diff suppressed because it is too large
Load Diff
@@ -66,7 +66,7 @@ async function main() {
|
||||
"commerce-modules"
|
||||
),
|
||||
allowedFilesPatterns: [
|
||||
/^(?!.*\/(workflows|js-sdk|extend|events|admin-widget-zones)\/).*$/,
|
||||
/^(?!.*\/(workflows|js-sdk|extend|admin-widget-zones)\/).*$/,
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -101,6 +101,16 @@ async function main() {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
dir: path.join(
|
||||
process.cwd(),
|
||||
"..",
|
||||
"resources",
|
||||
"references",
|
||||
"modules",
|
||||
"events"
|
||||
),
|
||||
},
|
||||
{
|
||||
dir: path.join(process.cwd(), "..", "resources", "app", "medusa-cli"),
|
||||
},
|
||||
|
||||
@@ -197,7 +197,7 @@ const priceSet = await pricingModuleService.createPriceSets({
|
||||
amount: 200,
|
||||
currency_code: "EUR",
|
||||
min_quantity: 100,
|
||||
}
|
||||
},
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
@@ -101,10 +101,10 @@ const { result } = await createProductsWorkflow(container)
|
||||
},
|
||||
],
|
||||
// ...
|
||||
}]
|
||||
}],
|
||||
}],
|
||||
// ...
|
||||
}
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
@@ -217,8 +217,8 @@ To create the Bundled Product Module's service, create the file `src/modules/bun
|
||||
|
||||
```ts title="src/modules/bundled-product/service.ts"
|
||||
import { MedusaService } from "@medusajs/framework/utils"
|
||||
import { Bundle } from "./models/bundle";
|
||||
import { BundleItem } from "./models/bundle-item";
|
||||
import { Bundle } from "./models/bundle"
|
||||
import { BundleItem } from "./models/bundle-item"
|
||||
|
||||
export default class BundledProductModuleService extends MedusaService({
|
||||
Bundle,
|
||||
@@ -338,9 +338,9 @@ You can define links between data models in a TypeScript or JavaScript file unde
|
||||
So, to define the link between a bundle and a product, create the file `src/links/bundle-product.ts` with the following content:
|
||||
|
||||
```ts title="src/links/bundle-product.ts"
|
||||
import { defineLink } from "@medusajs/framework/utils";
|
||||
import ProductModule from "@medusajs/medusa/product";
|
||||
import BundledProductsModule from "../modules/bundled-product";
|
||||
import { defineLink } from "@medusajs/framework/utils"
|
||||
import ProductModule from "@medusajs/medusa/product"
|
||||
import BundledProductsModule from "../modules/bundled-product"
|
||||
|
||||
export default defineLink(
|
||||
BundledProductsModule.linkable.bundle,
|
||||
@@ -360,9 +360,9 @@ You'll later learn how to query and manage the linked records.
|
||||
Next, you'll define the link between the `BundleItem` data model and the `Product` data model. Create the file `src/links/bundle-item-product.ts` with the following content:
|
||||
|
||||
```ts title="src/links/bundle-item-product.ts"
|
||||
import { defineLink } from "@medusajs/framework/utils";
|
||||
import ProductModule from "@medusajs/medusa/product";
|
||||
import BundledProductsModule from "../modules/bundled-product";
|
||||
import { defineLink } from "@medusajs/framework/utils"
|
||||
import ProductModule from "@medusajs/medusa/product"
|
||||
import BundledProductsModule from "../modules/bundled-product"
|
||||
|
||||
export default defineLink(
|
||||
{
|
||||
@@ -579,13 +579,13 @@ export const createBundleItemsStep = createStep(
|
||||
container.resolve(BUNDLED_PRODUCT_MODULE)
|
||||
|
||||
const bundleItems = await bundledProductModuleService.createBundleItems(
|
||||
items.map(item => ({
|
||||
items.map((item) => ({
|
||||
bundle_id,
|
||||
quantity: item.quantity,
|
||||
}))
|
||||
)
|
||||
|
||||
return new StepResponse(bundleItems, bundleItems.map(item => item.id))
|
||||
return new StepResponse(bundleItems, bundleItems.map((item) => item.id))
|
||||
},
|
||||
async (itemIds, { container }) => {
|
||||
if (!itemIds?.length) {
|
||||
@@ -657,7 +657,7 @@ export const createBundledProductWorkflow = createWorkflow(
|
||||
const bundleProduct = createProductsWorkflow.runAsStep({
|
||||
input: {
|
||||
products: [bundleData.product],
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
createRemoteLinkStep([{
|
||||
@@ -671,7 +671,7 @@ export const createBundledProductWorkflow = createWorkflow(
|
||||
|
||||
const bundleProducttemLinks = transform({
|
||||
bundleData,
|
||||
bundleItems
|
||||
bundleItems,
|
||||
}, (data) => {
|
||||
return data.bundleItems.map((item, index) => ({
|
||||
[BUNDLED_PRODUCT_MODULE]: {
|
||||
@@ -758,16 +758,16 @@ export const bundledProductsRouteHighlights = [
|
||||
```ts title="src/api/admin/bundled-products/route.ts" highlights={bundledProductsRouteHighlights}
|
||||
import {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse
|
||||
} from "@medusajs/framework/http";
|
||||
import { z } from "zod";
|
||||
MedusaResponse,
|
||||
} from "@medusajs/framework/http"
|
||||
import { z } from "zod"
|
||||
import {
|
||||
AdminCreateProduct
|
||||
AdminCreateProduct,
|
||||
} from "@medusajs/medusa/api/admin/products/validators"
|
||||
import {
|
||||
createBundledProductWorkflow,
|
||||
CreateBundledProductWorkflowInput
|
||||
} from "../../../workflows/create-bundled-product";
|
||||
CreateBundledProductWorkflowInput,
|
||||
} from "../../../workflows/create-bundled-product"
|
||||
|
||||
export const PostBundledProductsSchema = z.object({
|
||||
title: z.string(),
|
||||
@@ -785,12 +785,12 @@ export async function POST(
|
||||
res: MedusaResponse
|
||||
) {
|
||||
const {
|
||||
result: bundledProduct
|
||||
result: bundledProduct,
|
||||
} = await createBundledProductWorkflow(req.scope)
|
||||
.run({
|
||||
input: {
|
||||
bundle: req.validatedBody,
|
||||
} as CreateBundledProductWorkflowInput
|
||||
} as CreateBundledProductWorkflowInput,
|
||||
})
|
||||
|
||||
res.json({
|
||||
@@ -843,9 +843,9 @@ export const middlewaresHighlights = [
|
||||
```ts title="src/api/middlewares.ts" highlights={middlewaresHighlights}
|
||||
import {
|
||||
defineMiddlewares,
|
||||
validateAndTransformBody
|
||||
} from "@medusajs/framework/http";
|
||||
import { PostBundledProductsSchema } from "./admin/bundled-products/route";
|
||||
validateAndTransformBody,
|
||||
} from "@medusajs/framework/http"
|
||||
import { PostBundledProductsSchema } from "./admin/bundled-products/route"
|
||||
|
||||
export default defineMiddlewares({
|
||||
routes: [
|
||||
@@ -856,7 +856,7 @@ export default defineMiddlewares({
|
||||
validateAndTransformBody(PostBundledProductsSchema),
|
||||
],
|
||||
},
|
||||
]
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
@@ -893,10 +893,10 @@ export async function GET(
|
||||
|
||||
const {
|
||||
data: bundledProducts,
|
||||
metadata: { count, take, skip } = {}
|
||||
metadata: { count, take, skip } = {},
|
||||
} = await query.graph({
|
||||
entity: "bundle",
|
||||
...req.queryConfig
|
||||
...req.queryConfig,
|
||||
})
|
||||
|
||||
res.json({
|
||||
@@ -932,8 +932,8 @@ export const getBundledProductsMiddlewareHighlights = [
|
||||
|
||||
```ts title="src/api/middlewares.ts" highlights={getBundledProductsMiddlewareHighlights}
|
||||
// other imports...
|
||||
import { validateAndTransformQuery } from "@medusajs/framework/http";
|
||||
import { createFindParams } from "@medusajs/medusa/api/utils/validators";
|
||||
import { validateAndTransformQuery } from "@medusajs/framework/http"
|
||||
import { createFindParams } from "@medusajs/medusa/api/utils/validators"
|
||||
|
||||
export default defineMiddlewares({
|
||||
routes: [
|
||||
@@ -955,7 +955,7 @@ export default defineMiddlewares({
|
||||
}),
|
||||
],
|
||||
},
|
||||
]
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
@@ -1253,7 +1253,7 @@ import {
|
||||
Input,
|
||||
Label,
|
||||
Select,
|
||||
toast
|
||||
toast,
|
||||
} from "@medusajs/ui"
|
||||
import { useState, useRef, useCallback, useMemo } from "react"
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"
|
||||
@@ -1270,7 +1270,7 @@ const CreateBundledProduct = () => {
|
||||
{
|
||||
product_id: undefined,
|
||||
quantity: 1,
|
||||
}
|
||||
},
|
||||
])
|
||||
// TODO fetch products
|
||||
}
|
||||
@@ -1303,8 +1303,9 @@ const [products, setProducts] = useState<HttpTypes.AdminProduct[]>([])
|
||||
const productsLimit = 15
|
||||
const [currnetProductPage, setCurrentProductPage] = useState(0)
|
||||
const [productsCount, setProductsCount] = useState(0)
|
||||
const hasNextPage = useMemo(() =>
|
||||
productsCount ? productsCount > productsLimit : true,
|
||||
const hasNextPage = useMemo(() => {
|
||||
return productsCount ? productsCount > productsLimit : true
|
||||
},
|
||||
[productsCount, productsLimit])
|
||||
const queryClient = useQueryClient()
|
||||
useQuery({
|
||||
@@ -1353,14 +1354,14 @@ export const createBundledProductComponentHighlights3 = [
|
||||
```tsx title="src/admin/components/create-bundled-product.tsx" highlights={createBundledProductComponentHighlights3}
|
||||
const {
|
||||
mutateAsync: createBundledProduct,
|
||||
isPending: isCreating
|
||||
isPending: isCreating,
|
||||
} = useMutation({
|
||||
mutationFn: async (data: Record<string, any>) => {
|
||||
await sdk.client.fetch("/admin/bundled-products", {
|
||||
method: "POST",
|
||||
body: data
|
||||
body: data,
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const handleCreate = async () => {
|
||||
@@ -1372,8 +1373,8 @@ const handleCreate = async () => {
|
||||
options: [
|
||||
{
|
||||
title: "Default",
|
||||
values: ["default"]
|
||||
}
|
||||
values: ["default"],
|
||||
},
|
||||
],
|
||||
status: "published",
|
||||
variants: [
|
||||
@@ -1382,21 +1383,21 @@ const handleCreate = async () => {
|
||||
// You can set prices in the product's page
|
||||
prices: [],
|
||||
options: {
|
||||
Default: "default"
|
||||
Default: "default",
|
||||
},
|
||||
manage_inventory: false
|
||||
}
|
||||
]
|
||||
manage_inventory: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
items: items.map((item) => ({
|
||||
product_id: item.product_id,
|
||||
quantity: item.quantity,
|
||||
}))
|
||||
})),
|
||||
})
|
||||
setOpen(false)
|
||||
toast.success("Bundled product created successfully")
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["bundled-products"]
|
||||
queryKey: ["bundled-products"],
|
||||
})
|
||||
setTitle("")
|
||||
setItems([{ product_id: undefined, quantity: 1 }])
|
||||
@@ -1452,7 +1453,7 @@ const BundledProductItem = ({
|
||||
setItems,
|
||||
products,
|
||||
fetchMoreProducts,
|
||||
hasNextPage
|
||||
hasNextPage,
|
||||
}: BundledProductItemProps) => {
|
||||
const observer = useRef(
|
||||
new IntersectionObserver(
|
||||
@@ -1491,14 +1492,14 @@ const BundledProductItem = ({
|
||||
value={item.product_id}
|
||||
onValueChange={(value) =>
|
||||
setItems((items) =>
|
||||
items.map((item, i) =>
|
||||
i === index
|
||||
items.map((item, i) => {
|
||||
return i === index
|
||||
? {
|
||||
...item,
|
||||
product_id: value,
|
||||
}
|
||||
: item
|
||||
)
|
||||
})
|
||||
)
|
||||
}
|
||||
>
|
||||
@@ -1530,11 +1531,11 @@ const BundledProductItem = ({
|
||||
value={item.quantity}
|
||||
onChange={(e) =>
|
||||
setItems((items) =>
|
||||
items.map((item, i) =>
|
||||
i === index
|
||||
items.map((item, i) => {
|
||||
return i === index
|
||||
? { ...item, quantity: parseInt(e.target.value) }
|
||||
: item
|
||||
)
|
||||
})
|
||||
)
|
||||
}
|
||||
/>
|
||||
@@ -1838,8 +1839,8 @@ export const prepareBundleCartDataStep = createStep(
|
||||
quantity: item.quantity * quantity,
|
||||
metadata: {
|
||||
bundle_id: bundle.id,
|
||||
quantity: quantity
|
||||
}
|
||||
quantity: quantity,
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1869,8 +1870,8 @@ return {
|
||||
unit_price: 100,
|
||||
metadata: {
|
||||
bundle_id: bundle.id,
|
||||
quantity: quantity
|
||||
}
|
||||
quantity: quantity,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1895,15 +1896,15 @@ export const addBundleToCartWorkflowHighlights = [
|
||||
import {
|
||||
createWorkflow,
|
||||
transform,
|
||||
WorkflowResponse
|
||||
WorkflowResponse,
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
import {
|
||||
addToCartWorkflow,
|
||||
useQueryGraphStep
|
||||
useQueryGraphStep,
|
||||
} from "@medusajs/medusa/core-flows"
|
||||
import {
|
||||
prepareBundleCartDataStep,
|
||||
PrepareBundleCartDataStepInput
|
||||
PrepareBundleCartDataStepInput,
|
||||
} from "./steps/prepare-bundle-cart-data"
|
||||
|
||||
type AddBundleToCartWorkflowInput = {
|
||||
@@ -1926,27 +1927,27 @@ export const addBundleToCartWorkflow = createWorkflow(
|
||||
"id",
|
||||
"items.*",
|
||||
"items.product.*",
|
||||
"items.product.variants.*"
|
||||
"items.product.variants.*",
|
||||
],
|
||||
filters: {
|
||||
id: bundle_id
|
||||
id: bundle_id,
|
||||
},
|
||||
options: {
|
||||
throwIfKeyNotFound: true
|
||||
}
|
||||
throwIfKeyNotFound: true,
|
||||
},
|
||||
})
|
||||
|
||||
const itemsToAdd = prepareBundleCartDataStep({
|
||||
bundle: data[0],
|
||||
quantity,
|
||||
items
|
||||
items,
|
||||
} as unknown as PrepareBundleCartDataStepInput)
|
||||
|
||||
addToCartWorkflow.runAsStep({
|
||||
input: {
|
||||
cart_id,
|
||||
items: itemsToAdd
|
||||
}
|
||||
items: itemsToAdd,
|
||||
},
|
||||
})
|
||||
|
||||
// @ts-ignore
|
||||
@@ -1979,19 +1980,19 @@ You'll now create the API route that exposes the workflow's functionalities to s
|
||||
To create the API route, create the file `src/api/store/carts/[id]/line-item-bundles/route.ts` with the following content:
|
||||
|
||||
```ts title="src/api/store/carts/[id]/line-item-bundles/route.ts" collapsibleLines="1-6" expandButtonLabel="Show Imports"
|
||||
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http";
|
||||
import { z } from "zod";
|
||||
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
|
||||
import { z } from "zod"
|
||||
import {
|
||||
addBundleToCartWorkflow
|
||||
} from "../../../../../workflows/add-bundle-to-cart";
|
||||
addBundleToCartWorkflow,
|
||||
} from "../../../../../workflows/add-bundle-to-cart"
|
||||
|
||||
export const PostCartsBundledLineItemsSchema = z.object({
|
||||
bundle_id: z.string(),
|
||||
quantity: z.number().default(1),
|
||||
items: z.array(z.object({
|
||||
item_id: z.string(),
|
||||
variant_id: z.string()
|
||||
}))
|
||||
variant_id: z.string(),
|
||||
})),
|
||||
})
|
||||
|
||||
type PostCartsBundledLineItemsSchema = z.infer<
|
||||
@@ -2008,12 +2009,12 @@ export async function POST(
|
||||
cart_id: req.params.id,
|
||||
bundle_id: req.validatedBody.bundle_id,
|
||||
quantity: req.validatedBody.quantity || 1,
|
||||
items: req.validatedBody.items
|
||||
}
|
||||
items: req.validatedBody.items,
|
||||
},
|
||||
})
|
||||
|
||||
res.json({
|
||||
cart
|
||||
cart,
|
||||
})
|
||||
}
|
||||
```
|
||||
@@ -2039,8 +2040,8 @@ In `src/api/middlewares.ts`, add a new middleware object to the `routes` array:
|
||||
```ts title="src/api/middlewares.ts"
|
||||
// other imports...
|
||||
import {
|
||||
PostCartsBundledLineItemsSchema
|
||||
} from "./store/carts/[id]/line-item-bundles/route";
|
||||
PostCartsBundledLineItemsSchema,
|
||||
} from "./store/carts/[id]/line-item-bundles/route"
|
||||
|
||||
export default defineMiddlewares({
|
||||
routes: [
|
||||
@@ -2049,10 +2050,10 @@ export default defineMiddlewares({
|
||||
matcher: "/store/carts/:id/line-item-bundles",
|
||||
methods: ["POST"],
|
||||
middlewares: [
|
||||
validateAndTransformBody(PostCartsBundledLineItemsSchema)
|
||||
validateAndTransformBody(PostCartsBundledLineItemsSchema),
|
||||
],
|
||||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
@@ -2076,8 +2077,8 @@ export const bundleProductsRouteHighlights = [
|
||||
]
|
||||
|
||||
```ts title="src/api/store/bundle-products/[id]/route.ts" highlights={bundleProductsRouteHighlights}
|
||||
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http";
|
||||
import { QueryContext } from "@medusajs/framework/utils";
|
||||
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
|
||||
import { QueryContext } from "@medusajs/framework/utils"
|
||||
|
||||
export async function GET(
|
||||
req: MedusaRequest,
|
||||
@@ -2100,7 +2101,7 @@ export async function GET(
|
||||
"items.product.variants.options.*",
|
||||
],
|
||||
filters: {
|
||||
id
|
||||
id,
|
||||
},
|
||||
context: {
|
||||
items: {
|
||||
@@ -2111,16 +2112,16 @@ export async function GET(
|
||||
currency_code,
|
||||
}),
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
}, {
|
||||
throwIfKeyNotFound: true
|
||||
throwIfKeyNotFound: true,
|
||||
})
|
||||
|
||||
res.json({
|
||||
bundle_product: data[0]
|
||||
bundle_product: data[0],
|
||||
})
|
||||
}
|
||||
```
|
||||
@@ -2283,7 +2284,7 @@ const pricedProduct = await listProducts({
|
||||
countryCode: params.countryCode,
|
||||
queryParams: {
|
||||
handle: params.handle,
|
||||
fields: "*bundle"
|
||||
fields: "*bundle",
|
||||
},
|
||||
}).then(({ response }) => response.products[0])
|
||||
```
|
||||
@@ -2313,7 +2314,7 @@ export async function addBundleToCart({
|
||||
bundleId,
|
||||
quantity,
|
||||
countryCode,
|
||||
items
|
||||
items,
|
||||
}: {
|
||||
bundleId: string
|
||||
quantity: number
|
||||
@@ -2344,7 +2345,7 @@ export async function addBundleToCart({
|
||||
body: {
|
||||
bundle_id: bundleId,
|
||||
quantity,
|
||||
items
|
||||
items,
|
||||
},
|
||||
headers,
|
||||
})
|
||||
@@ -2442,7 +2443,7 @@ export const bundleActionsComponentHighlights2 = [
|
||||
// For each product, if it has only 1 variant, preselect it
|
||||
useEffect(() => {
|
||||
const initialOptions: Record<string, Record<string, string>> = {}
|
||||
bundle.items.forEach(item => {
|
||||
bundle.items.forEach((item) => {
|
||||
if (item.product.variants?.length === 1) {
|
||||
const variantOptions = optionsAsKeymap(item.product.variants[0].options)
|
||||
initialOptions[item.product.id] = variantOptions ?? {}
|
||||
@@ -2454,10 +2455,10 @@ useEffect(() => {
|
||||
}, [bundle.items])
|
||||
|
||||
const selectedVariants = useMemo(() => {
|
||||
return bundle.items.map(item => {
|
||||
if (!item.product.variants || item.product.variants.length === 0) return undefined
|
||||
return bundle.items.map((item) => {
|
||||
if (!item.product.variants || item.product.variants.length === 0) {return undefined}
|
||||
|
||||
return item.product.variants.find(v => {
|
||||
return item.product.variants.find((v) => {
|
||||
const variantOptions = optionsAsKeymap(v.options)
|
||||
return isEqual(variantOptions, productOptions[item.product.id])
|
||||
})
|
||||
@@ -2465,17 +2466,17 @@ const selectedVariants = useMemo(() => {
|
||||
}, [bundle.items, productOptions])
|
||||
|
||||
const setOptionValue = (productId: string, optionId: string, value: string) => {
|
||||
setProductOptions(prev => ({
|
||||
setProductOptions((prev) => ({
|
||||
...prev,
|
||||
[productId]: {
|
||||
...prev[productId],
|
||||
[optionId]: value,
|
||||
}
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
const allVariantsSelected = useMemo(() => {
|
||||
return selectedVariants.every(v => v !== undefined)
|
||||
return selectedVariants.every((v) => v !== undefined)
|
||||
}, [selectedVariants])
|
||||
|
||||
// TODO handle add to cart
|
||||
@@ -2497,7 +2498,7 @@ Replace the `TODO` in the `BundleActions` component with the following code:
|
||||
|
||||
```tsx title="src/modules/products/components/bundle-actions/index.tsx" badgeLabel="Storefront" badgeColor="blue"
|
||||
const handleAddToCart = async () => {
|
||||
if (!allVariantsSelected) return
|
||||
if (!allVariantsSelected) {return}
|
||||
|
||||
setIsAdding(true)
|
||||
await addBundleToCart({
|
||||
@@ -2541,6 +2542,7 @@ Then, in the `return` statement, pass the `className` prop in the classes of the
|
||||
className={clx("text-xl-semi", {
|
||||
"text-ui-fg-interactive": selectedPrice.price_type === "sale",
|
||||
}, className)}
|
||||
>
|
||||
{/* ... */}
|
||||
</span>
|
||||
</div>
|
||||
@@ -2805,11 +2807,11 @@ export const removeBundleFromCartWorkflowHighlights = [
|
||||
import {
|
||||
createWorkflow,
|
||||
transform,
|
||||
WorkflowResponse
|
||||
WorkflowResponse,
|
||||
} from "@medusajs/framework/workflows-sdk"
|
||||
import {
|
||||
deleteLineItemsWorkflow,
|
||||
useQueryGraphStep
|
||||
useQueryGraphStep,
|
||||
} from "@medusajs/medusa/core-flows"
|
||||
|
||||
type RemoveBundleFromCartWorkflowInput = {
|
||||
@@ -2831,7 +2833,7 @@ export const removeBundleFromCartWorkflow = createWorkflow(
|
||||
},
|
||||
options: {
|
||||
throwIfKeyNotFound: true,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const itemsToRemove = transform({
|
||||
@@ -2847,7 +2849,7 @@ export const removeBundleFromCartWorkflow = createWorkflow(
|
||||
input: {
|
||||
cart_id,
|
||||
ids: itemsToRemove,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
// retrieve cart again
|
||||
@@ -2886,10 +2888,10 @@ Next, you'll create the API route that exposes the workflow's functionality to s
|
||||
Create the file `src/api/store/carts/[id]/line-item-bundles/[bundle_id]/route.ts` with the following content:
|
||||
|
||||
```ts title="src/api/store/carts/[id]/line-item-bundles/[bundle_id]/route.ts"
|
||||
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http";
|
||||
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
|
||||
import {
|
||||
removeBundleFromCartWorkflow
|
||||
} from "../../../../../../workflows/remove-bundle-from-cart";
|
||||
removeBundleFromCartWorkflow,
|
||||
} from "../../../../../../workflows/remove-bundle-from-cart"
|
||||
|
||||
export async function DELETE(
|
||||
req: MedusaRequest,
|
||||
@@ -2900,11 +2902,11 @@ export async function DELETE(
|
||||
input: {
|
||||
cart_id: req.params.id,
|
||||
bundle_id: req.params.bundle_id,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
res.json({
|
||||
cart
|
||||
cart,
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
"use client"
|
||||
|
||||
import { Brackets, CheckCircle, SquareTwoStack, Tag } from "@medusajs/icons"
|
||||
import {
|
||||
DropdownMenu,
|
||||
H2,
|
||||
H2Props,
|
||||
H3,
|
||||
H3Props,
|
||||
useCopy,
|
||||
useGenerateSnippet,
|
||||
} from "docs-ui"
|
||||
|
||||
type EventHeaderProps = (
|
||||
| {
|
||||
headerLvl: "2"
|
||||
headerProps: H2Props
|
||||
}
|
||||
| {
|
||||
headerLvl: "3"
|
||||
headerProps: H3Props
|
||||
}
|
||||
) & {
|
||||
eventName: string
|
||||
payload: string
|
||||
}
|
||||
|
||||
export const EventHeader = ({
|
||||
headerLvl,
|
||||
headerProps,
|
||||
eventName,
|
||||
payload: payloadStr,
|
||||
}: EventHeaderProps) => {
|
||||
const Header = headerLvl === "2" ? H2 : H3
|
||||
const { snippet } = useGenerateSnippet({
|
||||
type: "subscriber",
|
||||
options: {
|
||||
event: eventName,
|
||||
payload: payloadStr,
|
||||
},
|
||||
})
|
||||
const { handleCopy: handleEventNameCopy, isCopied: eventNameCopied } =
|
||||
useCopy(eventName)
|
||||
const { handleCopy: handleSnippetCopy, isCopied: snippetCopied } =
|
||||
useCopy(snippet)
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between flex-wrap">
|
||||
<Header {...headerProps}>{eventName}</Header>
|
||||
<DropdownMenu
|
||||
dropdownButtonContent={
|
||||
<>
|
||||
{eventNameCopied || snippetCopied ? (
|
||||
<CheckCircle />
|
||||
) : (
|
||||
<SquareTwoStack />
|
||||
)}
|
||||
</>
|
||||
}
|
||||
menuItems={[
|
||||
{
|
||||
type: "action",
|
||||
title: "Copy event name",
|
||||
action: () => handleEventNameCopy(),
|
||||
icon: <Tag />,
|
||||
},
|
||||
{
|
||||
type: "action",
|
||||
title: "Copy subscriber for event",
|
||||
action: () => handleSnippetCopy(),
|
||||
icon: <Brackets />,
|
||||
},
|
||||
]}
|
||||
menuClassName="z-10"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -10,8 +10,10 @@ import {
|
||||
Table,
|
||||
Badge,
|
||||
Tooltip,
|
||||
CopyGeneratedSnippetButton,
|
||||
} from "docs-ui"
|
||||
import { CommerceModuleSections } from "../CommerceModuleSections"
|
||||
import { EventHeader } from "../EventHeader"
|
||||
|
||||
const MDXComponents: MDXComponentsType = {
|
||||
...UiMdxComponents,
|
||||
@@ -27,6 +29,8 @@ const MDXComponents: MDXComponentsType = {
|
||||
Tooltip: (props) => {
|
||||
return <Tooltip {...props} />
|
||||
},
|
||||
EventHeader,
|
||||
CopyGeneratedSnippetButton,
|
||||
}
|
||||
|
||||
export default MDXComponents
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,7 @@
|
||||
"dependencies": {
|
||||
"@mdx-js/loader": "^3.1.0",
|
||||
"@mdx-js/react": "^3.1.0",
|
||||
"@medusajs/icons": "~2.5.1",
|
||||
"@medusajs/icons": "~2.7.1",
|
||||
"@next/mdx": "15.3.1",
|
||||
"clsx": "^2.1.0",
|
||||
"docs-ui": "*",
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
"dependencies": {
|
||||
"@faker-js/faker": "^8.0.2",
|
||||
"@mdx-js/react": "^3.1.0",
|
||||
"@medusajs/icons": "2.6.0",
|
||||
"@medusajs/ui": "4.0.6",
|
||||
"@medusajs/ui-preset": "2.6.0",
|
||||
"@medusajs/icons": "2.7.1",
|
||||
"@medusajs/ui": "4.0.9",
|
||||
"@medusajs/ui-preset": "2.7.1",
|
||||
"autoprefixer": "10.4.14",
|
||||
"build-scripts": "*",
|
||||
"clsx": "^2.0.0",
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
"dependencies": {
|
||||
"@mdx-js/loader": "^3.1.0",
|
||||
"@mdx-js/react": "^3.1.0",
|
||||
"@medusajs/icons": "~2.5.1",
|
||||
"@medusajs/icons": "~2.7.1",
|
||||
"@next/mdx": "15.0.4",
|
||||
"clsx": "^2.1.0",
|
||||
"docs-ui": "*",
|
||||
|
||||
@@ -57,8 +57,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/is-prop-valid": "^1.3.1",
|
||||
"@medusajs/icons": "2.6.0",
|
||||
"@medusajs/ui": "4.0.6",
|
||||
"@medusajs/icons": "2.7.1",
|
||||
"@medusajs/ui": "4.0.9",
|
||||
"@next/third-parties": "15.3.1",
|
||||
"@octokit/request": "^8.1.1",
|
||||
"@react-hook/resize-observer": "^1.2.6",
|
||||
|
||||
@@ -5,6 +5,10 @@ import clsx from "clsx"
|
||||
import { Tooltip } from "@/components"
|
||||
import { useCopy } from "../../hooks"
|
||||
|
||||
export type CopyButtonChildFn = (props: {
|
||||
isCopied: boolean
|
||||
}) => React.ReactNode
|
||||
|
||||
export type CopyButtonProps = {
|
||||
text: string
|
||||
buttonClassName?: string
|
||||
@@ -17,7 +21,8 @@ export type CopyButtonProps = {
|
||||
| React.TouchEvent<HTMLSpanElement>
|
||||
) => void
|
||||
handleTouch?: boolean
|
||||
} & Omit<React.HTMLAttributes<HTMLDivElement>, "onCopy">
|
||||
children?: React.ReactNode | CopyButtonChildFn
|
||||
} & Omit<React.HTMLAttributes<HTMLDivElement>, "onCopy" | "children">
|
||||
|
||||
export const CopyButton = ({
|
||||
text,
|
||||
@@ -64,7 +69,7 @@ export const CopyButton = ({
|
||||
}
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
{typeof children === "function" ? children({ isCopied }) : children}
|
||||
</span>
|
||||
</Tooltip>
|
||||
)
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
"use client"
|
||||
|
||||
import React from "react"
|
||||
import { CopyButton, useGenerateSnippet, UseGenerateSnippet } from "../.."
|
||||
import { SquareTwoStack, CheckCircle } from "@medusajs/icons"
|
||||
|
||||
export type CopyGeneratedSnippetButtonProps = UseGenerateSnippet & {
|
||||
tooltipText?: string
|
||||
}
|
||||
|
||||
export const CopyGeneratedSnippetButton = ({
|
||||
tooltipText,
|
||||
...props
|
||||
}: CopyGeneratedSnippetButtonProps) => {
|
||||
const { snippet } = useGenerateSnippet(props)
|
||||
|
||||
return (
|
||||
<CopyButton
|
||||
text={snippet}
|
||||
tooltipText={tooltipText}
|
||||
className="inline-block w-fit"
|
||||
>
|
||||
{({ isCopied }) => {
|
||||
if (isCopied) {
|
||||
return <CheckCircle />
|
||||
}
|
||||
return <SquareTwoStack />
|
||||
}}
|
||||
</CopyButton>
|
||||
)
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import clsx from "clsx"
|
||||
import React from "react"
|
||||
import { LlmDropdown } from "../../LlmDropdown"
|
||||
|
||||
type H1Props = React.HTMLAttributes<HTMLHeadingElement> & {
|
||||
export type H1Props = React.HTMLAttributes<HTMLHeadingElement> & {
|
||||
id?: string
|
||||
hideLlmDropdown?: boolean
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import React from "react"
|
||||
import { CopyButton, Link } from "@/components"
|
||||
import { useHeadingUrl, useLayout } from "../../.."
|
||||
|
||||
type H2Props = React.HTMLAttributes<HTMLHeadingElement> & {
|
||||
export type H2Props = React.HTMLAttributes<HTMLHeadingElement> & {
|
||||
id?: string
|
||||
passRef?: React.RefObject<HTMLHeadingElement | null>
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import React from "react"
|
||||
import { CopyButton, Link } from "@/components"
|
||||
import { useHeadingUrl, useLayout } from "../../.."
|
||||
|
||||
type H3Props = React.HTMLAttributes<HTMLHeadingElement> & {
|
||||
export type H3Props = React.HTMLAttributes<HTMLHeadingElement> & {
|
||||
id?: string
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ export const H4 = ({
|
||||
}: React.HTMLAttributes<HTMLHeadingElement>) => {
|
||||
return (
|
||||
<h4
|
||||
className={clsx("mb-docs_0.5 text-medusa-fg-base text-h4", className)}
|
||||
className={clsx("mb-docs_1 text-medusa-fg-base text-h4", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -3,9 +3,8 @@
|
||||
import React, { useRef, useState } from "react"
|
||||
import { useAiAssistant, useSiteConfig } from "../../providers"
|
||||
import { usePathname } from "next/navigation"
|
||||
import { Button } from "../Button"
|
||||
import { AiAssistent, Book } from "@medusajs/icons"
|
||||
import { Menu } from "../Menu"
|
||||
import { DropdownMenu, Menu } from "../Menu"
|
||||
import { MarkdownIcon } from "../Icons/Markdown"
|
||||
import { useAiAssistantChat } from "../../providers/AiAssistant/Chat"
|
||||
import clsx from "clsx"
|
||||
@@ -30,43 +29,41 @@ export const LlmDropdown = () => {
|
||||
const pageUrl = `${baseUrl}${basePath}${pathname}`
|
||||
|
||||
return (
|
||||
<div className="relative hidden md:block">
|
||||
<Button
|
||||
variant="transparent"
|
||||
onClick={() => setOpen(!open)}
|
||||
className="!p-[6px] text-medusa-fg-subtle"
|
||||
buttonRef={ref}
|
||||
>
|
||||
<Book />
|
||||
</Button>
|
||||
<Menu
|
||||
items={[
|
||||
{
|
||||
type: "link",
|
||||
title: "View as Markdown",
|
||||
link: `${pageUrl}/index.html.md`,
|
||||
icon: <MarkdownIcon width={19} height={19} />,
|
||||
openInNewTab: true,
|
||||
},
|
||||
{
|
||||
type: "action",
|
||||
title: "Ask AI Assistant",
|
||||
action: () => {
|
||||
if (loading) {
|
||||
return
|
||||
}
|
||||
setQuestion(`Explain the page ${pageUrl}`)
|
||||
setChatOpened(true)
|
||||
setOpen(false)
|
||||
<DropdownMenu
|
||||
open={open}
|
||||
setOpen={setOpen}
|
||||
dropdownButtonContent={<Book />}
|
||||
menuComponent={
|
||||
<Menu
|
||||
items={[
|
||||
{
|
||||
type: "link",
|
||||
title: "View as Markdown",
|
||||
link: `${pageUrl}/index.html.md`,
|
||||
icon: <MarkdownIcon width={19} height={19} />,
|
||||
openInNewTab: true,
|
||||
},
|
||||
icon: <AiAssistent />,
|
||||
},
|
||||
]}
|
||||
className={clsx(
|
||||
"absolute right-0 top-[calc(100%+8px)] w-max",
|
||||
!open && "hidden"
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
{
|
||||
type: "action",
|
||||
title: "Ask AI Assistant",
|
||||
action: () => {
|
||||
if (loading) {
|
||||
return
|
||||
}
|
||||
setQuestion(`Explain the page ${pageUrl}`)
|
||||
setChatOpened(true)
|
||||
setOpen(false)
|
||||
},
|
||||
icon: <AiAssistent />,
|
||||
},
|
||||
]}
|
||||
className={clsx(
|
||||
"absolute right-0 top-[calc(100%+8px)] w-max",
|
||||
!open && "hidden"
|
||||
)}
|
||||
/>
|
||||
}
|
||||
className="hidden md:block"
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
"use client"
|
||||
|
||||
import React from "react"
|
||||
import { useRef, useState } from "react"
|
||||
import { Button, Menu, useClickOutside } from "../../.."
|
||||
import { MenuItem } from "types"
|
||||
import clsx from "clsx"
|
||||
|
||||
type DropdownMenuProps = {
|
||||
dropdownButtonContent: React.ReactNode
|
||||
dropdownButtonClassName?: string
|
||||
menuComponent?: React.ReactNode
|
||||
menuItems?: MenuItem[]
|
||||
menuClassName?: string
|
||||
className?: string
|
||||
open?: boolean
|
||||
setOpen?: (open: boolean) => void
|
||||
}
|
||||
|
||||
export const DropdownMenu = ({
|
||||
dropdownButtonContent,
|
||||
dropdownButtonClassName,
|
||||
menuComponent,
|
||||
menuItems,
|
||||
menuClassName,
|
||||
className,
|
||||
open: externalOpen = false,
|
||||
setOpen: externalSetOpen,
|
||||
}: DropdownMenuProps) => {
|
||||
const [open, setOpen] = useState(externalOpen)
|
||||
const ref = useRef<HTMLButtonElement | null>(null)
|
||||
function changeOpenState(newOpenState: boolean) {
|
||||
if (externalSetOpen) {
|
||||
externalSetOpen(newOpenState)
|
||||
} else {
|
||||
setOpen(newOpenState)
|
||||
}
|
||||
}
|
||||
useClickOutside({
|
||||
elmRef: ref,
|
||||
onClickOutside: () => {
|
||||
changeOpenState(false)
|
||||
},
|
||||
})
|
||||
|
||||
if (!menuComponent && !menuItems) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={clsx("relative", className)}>
|
||||
<Button
|
||||
variant="transparent"
|
||||
onClick={() => changeOpenState(!open)}
|
||||
className={clsx(
|
||||
"!p-[6px] text-medusa-fg-subtle",
|
||||
dropdownButtonClassName
|
||||
)}
|
||||
buttonRef={ref}
|
||||
>
|
||||
{dropdownButtonContent}
|
||||
</Button>
|
||||
{menuComponent}
|
||||
{!menuComponent && menuItems && (
|
||||
<Menu
|
||||
items={menuItems}
|
||||
className={clsx(
|
||||
"absolute right-0 top-[calc(100%+8px)] w-max",
|
||||
!open && "hidden",
|
||||
menuClassName
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -39,3 +39,5 @@ export const Menu = ({ items, className, itemsOnClick }: MenuProps) => {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export * from "./Dropdown"
|
||||
|
||||
@@ -15,6 +15,7 @@ export * from "./CodeMdx"
|
||||
export * from "./CodeTabs"
|
||||
export * from "./CodeTabs/Item"
|
||||
export * from "./CopyButton"
|
||||
export * from "./CopyGeneratedSnippetButton"
|
||||
export * from "./Details"
|
||||
export * from "./Details/Summary"
|
||||
export * from "./DetailsList"
|
||||
|
||||
@@ -5,6 +5,7 @@ export * from "./use-click-outside"
|
||||
export * from "./use-collapsible"
|
||||
export * from "./use-collapsible-code-lines"
|
||||
export * from "./use-copy"
|
||||
export * from "./use-generate-snippet"
|
||||
export * from "./use-heading-url"
|
||||
export * from "./use-current-learning-path"
|
||||
export * from "./use-is-external-link"
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import {
|
||||
subscriberSnippetGenerator,
|
||||
SubscriberSnippetGeneratorOptions,
|
||||
} from "./snippet-generators/subscriber"
|
||||
|
||||
export type UseGenerateSnippet = {
|
||||
type: "subscriber"
|
||||
options: SubscriberSnippetGeneratorOptions
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const generators: Record<string, (options: any) => string> = {
|
||||
subscriber: subscriberSnippetGenerator,
|
||||
}
|
||||
|
||||
export const useGenerateSnippet = ({ type, options }: UseGenerateSnippet) => {
|
||||
const snippet = generators[type](options)
|
||||
|
||||
return {
|
||||
snippet,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
import { parseEventPayload } from "../../../utils"
|
||||
|
||||
export type SubscriberSnippetGeneratorOptions = {
|
||||
event: string
|
||||
payload: Record<string, unknown> | string
|
||||
}
|
||||
|
||||
export const subscriberSnippetGenerator = ({
|
||||
event,
|
||||
payload: initialPayload,
|
||||
}: SubscriberSnippetGeneratorOptions) => {
|
||||
const payload =
|
||||
typeof initialPayload === "string"
|
||||
? parseEventPayload(initialPayload).payload_for_snippet
|
||||
: initialPayload
|
||||
// format subscriber name
|
||||
const subscriberName =
|
||||
event
|
||||
.split(".")
|
||||
.map((word) =>
|
||||
word.replace(/-./g, (match) => match.charAt(1).toUpperCase())
|
||||
)
|
||||
.map((word, index) => {
|
||||
if (index === 0) {
|
||||
return word.charAt(0).toLowerCase() + word.slice(1)
|
||||
}
|
||||
|
||||
return word.charAt(0).toUpperCase() + word.slice(1)
|
||||
})
|
||||
.join("") + "Handler"
|
||||
// format payload
|
||||
const payloadType: Record<string, unknown> = {}
|
||||
Object.keys(payload).forEach((key) => {
|
||||
const value = payload[key]
|
||||
if (Array.isArray(value)) {
|
||||
payloadType[key] = `${typeof value[0]}[]`
|
||||
} else {
|
||||
payloadType[key] = typeof value
|
||||
}
|
||||
})
|
||||
|
||||
const payloadString = JSON.stringify(payloadType, null, 2).replaceAll(
|
||||
/"/g,
|
||||
""
|
||||
)
|
||||
|
||||
// return the snippet
|
||||
return subscriberSnippet
|
||||
.replace("{{subscriberName}}", subscriberName)
|
||||
.replace("{{event}}", event)
|
||||
.replace("{{payload}}", payloadString)
|
||||
}
|
||||
|
||||
const subscriberSnippet = `import { SubscriberArgs, type SubscriberConfig } from "@medusajs/framework"
|
||||
|
||||
export default async function {{subscriberName}}({
|
||||
event: { data },
|
||||
container,
|
||||
}: SubscriberArgs<{{payload}}>) {
|
||||
// TODO handle event
|
||||
}
|
||||
|
||||
export const config: SubscriberConfig = {
|
||||
event: "{{event}}",
|
||||
}`
|
||||
@@ -0,0 +1,54 @@
|
||||
import { OpenAPI } from "types"
|
||||
|
||||
export function parseEventPayload(payloadStr: string) {
|
||||
const payloadParams = payloadStr.matchAll(/([\w_]+),? \/\/ (\(\w*\) )*(.*)/g)
|
||||
const payloadForSnippet: Record<string, unknown> = {}
|
||||
const payload = Array.from(payloadParams).map((match) => {
|
||||
const name = match[1]
|
||||
const type = (match[2]?.replace(/\(|\)/g, "") || "string").trim()
|
||||
const description = match[3]
|
||||
|
||||
if (type === "string") {
|
||||
payloadForSnippet[name] = "test"
|
||||
} else if (type === "number") {
|
||||
payloadForSnippet[name] = 1
|
||||
} else if (type === "boolean") {
|
||||
payloadForSnippet[name] = true
|
||||
} else if (type === "object") {
|
||||
payloadForSnippet[name] = {}
|
||||
} else if (type === "array") {
|
||||
payloadForSnippet[name] = [{}]
|
||||
}
|
||||
|
||||
return {
|
||||
name,
|
||||
type,
|
||||
description,
|
||||
}
|
||||
})
|
||||
return {
|
||||
parsed_payload: {
|
||||
type: "object",
|
||||
required: ["payload"],
|
||||
properties: {
|
||||
payload: {
|
||||
type: "object",
|
||||
description: "The payload emitted with the event",
|
||||
required: [...payload.map((param) => param.name)],
|
||||
properties: payload.reduce(
|
||||
(acc, curr) => {
|
||||
acc[curr.name] = {
|
||||
type: curr.type as OpenAPI.OpenAPIV3.NonArraySchemaObjectType,
|
||||
description: curr.description,
|
||||
properties: {},
|
||||
}
|
||||
return acc
|
||||
},
|
||||
{} as Record<string, OpenAPI.SchemaObject>
|
||||
),
|
||||
},
|
||||
},
|
||||
} as OpenAPI.SchemaObject,
|
||||
payload_for_snippet: payloadForSnippet,
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ export * from "./capitalize"
|
||||
export * from "./check-sidebar-item-visibility"
|
||||
export * from "./decode-str"
|
||||
export * from "./dom-utils"
|
||||
export * from "./event-parser"
|
||||
export * from "./get-link-with-base-path"
|
||||
export * from "./get-local-search"
|
||||
export * from "./get-navbar-items"
|
||||
|
||||
@@ -5,6 +5,8 @@ import {
|
||||
Expression,
|
||||
ExpressionJsVar,
|
||||
ExpressionJsVarLiteral,
|
||||
JSXElementExpression,
|
||||
JSXTextExpression,
|
||||
LiteralExpression,
|
||||
ObjectExpression,
|
||||
} from "types"
|
||||
@@ -64,7 +66,23 @@ function expressionToJs(
|
||||
data: (expression as LiteralExpression).value,
|
||||
} as ExpressionJsVarLiteral
|
||||
case "JSXElement":
|
||||
// ignore JSXElements
|
||||
return
|
||||
case "JSXFragment":
|
||||
// Only take text children
|
||||
let text = ""
|
||||
;(expression as JSXElementExpression).children.forEach((child) => {
|
||||
if (child.type !== "JSXText") {
|
||||
return
|
||||
}
|
||||
|
||||
text += (child as JSXTextExpression).value
|
||||
})
|
||||
return {
|
||||
original: {
|
||||
type: "Literal",
|
||||
value: text,
|
||||
raw: `"${text}"`,
|
||||
},
|
||||
data: text,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
parseComponentExample,
|
||||
parseComponentReference,
|
||||
parseDetails,
|
||||
parseEventHeader,
|
||||
parseHookValues,
|
||||
parseIconSearch,
|
||||
parseNote,
|
||||
@@ -48,6 +49,7 @@ const parsers: Record<string, ComponentParser> = {
|
||||
HookValues: parseHookValues,
|
||||
Colors: parseColors,
|
||||
SplitList: parseSplitList,
|
||||
EventHeader: parseEventHeader,
|
||||
}
|
||||
|
||||
const isComponentAllowed = (nodeName: string): boolean => {
|
||||
|
||||
@@ -951,6 +951,54 @@ export const parseSplitList: ComponentParser = (
|
||||
return [SKIP, index]
|
||||
}
|
||||
|
||||
export const parseEventHeader: ComponentParser = (
|
||||
node: UnistNodeWithData,
|
||||
index: number,
|
||||
parent: UnistTree
|
||||
): VisitorResult => {
|
||||
const headerContent = node.attributes?.find(
|
||||
(attr) => attr.name === "headerProps"
|
||||
)
|
||||
const headerLvl = node.attributes?.find((attr) => attr.name === "headerLvl")
|
||||
|
||||
if (
|
||||
!headerContent ||
|
||||
typeof headerContent.value === "string" ||
|
||||
!headerContent.value.data?.estree ||
|
||||
!headerLvl ||
|
||||
typeof headerLvl.value !== "string" ||
|
||||
!headerLvl.value
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
const headerPropsJsVar = estreeToJs(headerContent.value.data.estree)
|
||||
|
||||
if (
|
||||
!isExpressionJsVarObj(headerPropsJsVar) ||
|
||||
!("children" in headerPropsJsVar) ||
|
||||
!isExpressionJsVarLiteral(headerPropsJsVar.children)
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
const headerLevel = parseInt(headerLvl.value, 10)
|
||||
const headerChildren = headerPropsJsVar.children.data as string
|
||||
|
||||
const headerChildrenNode = {
|
||||
type: "text",
|
||||
value: headerChildren,
|
||||
}
|
||||
const headerNode = {
|
||||
type: "heading",
|
||||
depth: headerLevel,
|
||||
children: [headerChildrenNode],
|
||||
}
|
||||
|
||||
parent?.children.splice(index, 1, headerNode)
|
||||
return [SKIP, index]
|
||||
}
|
||||
|
||||
/**
|
||||
* Helpers
|
||||
*/
|
||||
@@ -964,11 +1012,13 @@ const getTextNode = (node: UnistNode): UnistNode | undefined => {
|
||||
textNode = child
|
||||
} else if (child.type === "paragraph") {
|
||||
textNode = getTextNode(child)
|
||||
} else if (child.type === "link") {
|
||||
textNode = getTextNode(child)
|
||||
} else if (child.value) {
|
||||
textNode = child
|
||||
}
|
||||
|
||||
return false
|
||||
return textNode !== undefined
|
||||
})
|
||||
|
||||
return textNode
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
"watch": "tsc --watch"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@medusajs/icons": "2.6.0",
|
||||
"@medusajs/icons": "2.7.1",
|
||||
"@types/node": "^20.11.20",
|
||||
"rimraf": "^5.0.5",
|
||||
"tsconfig": "*",
|
||||
|
||||
@@ -37,6 +37,17 @@ export type LiteralExpression = {
|
||||
raw: string
|
||||
}
|
||||
|
||||
export type JSXElementExpression = {
|
||||
type: "JSXElement" | "JSXFragment"
|
||||
children: Expression[]
|
||||
}
|
||||
|
||||
export type JSXTextExpression = {
|
||||
type: "JSXText"
|
||||
value: string
|
||||
raw: string
|
||||
}
|
||||
|
||||
export type Expression =
|
||||
| {
|
||||
type: string
|
||||
@@ -44,6 +55,8 @@ export type Expression =
|
||||
| ArrayExpression
|
||||
| ObjectExpression
|
||||
| LiteralExpression
|
||||
| JSXElementExpression
|
||||
| JSXTextExpression
|
||||
|
||||
export interface Estree {
|
||||
body?: {
|
||||
|
||||
+57
-22
@@ -67,7 +67,7 @@ function formatEventsType(
|
||||
eventVariable.name.replaceAll("WorkflowEvents", "")
|
||||
)
|
||||
if (showHeader) {
|
||||
content.push(`## ${header} Events`)
|
||||
content.push(`${"#".repeat(subtitleLevel - 1)} ${header} Events`)
|
||||
}
|
||||
content.push("")
|
||||
|
||||
@@ -93,9 +93,7 @@ function formatEventsType(
|
||||
.find((tag) => tag.tag === "@eventName")
|
||||
?.content.map((content) => content.text)
|
||||
.join("") || ""
|
||||
eventName = `[${eventName}](#${slugify(eventName.replace(".", ""), {
|
||||
lower: true,
|
||||
})})`
|
||||
eventName = `[${eventName}](#${getEventNameSlug(eventName)})`
|
||||
const eventDescription = event.comment?.summary
|
||||
.map((content) => content.text)
|
||||
.join("")
|
||||
@@ -149,32 +147,30 @@ function formatEventsType(
|
||||
const deprecatedTag = event.comment?.blockTags.find(
|
||||
(tag) => tag.tag === "@deprecated"
|
||||
)
|
||||
const deprecatedMessage = deprecatedTag?.content
|
||||
.map((content) => content.text)
|
||||
.join("")
|
||||
.trim()
|
||||
|
||||
content.push(`${subHeaderPrefix} \`${eventName}\``)
|
||||
content.push(
|
||||
getEventHeading({
|
||||
titleLevel: subtitleLevel,
|
||||
eventName: eventName || "",
|
||||
payload: eventPayload || "",
|
||||
deprecated: !!deprecatedTag,
|
||||
deprecatedMessage,
|
||||
})
|
||||
)
|
||||
content.push("")
|
||||
if (deprecatedTag) {
|
||||
const deprecationText = deprecatedTag.content
|
||||
.map((content) => content.text)
|
||||
.join("")
|
||||
.trim()
|
||||
if (deprecationText.length) {
|
||||
content.push(`<Tooltip text="${deprecationText}">`)
|
||||
}
|
||||
|
||||
content.push(`<Badge variant="orange">Deprecated</Badge>`)
|
||||
|
||||
if (deprecationText.length) {
|
||||
content.push(`</Tooltip>`)
|
||||
}
|
||||
content.push("")
|
||||
}
|
||||
content.push(eventDescription || "")
|
||||
content.push("")
|
||||
content.push(`${subHeaderPrefix}# Payload`)
|
||||
content.push("")
|
||||
content.push(eventPayload || "")
|
||||
content.push("")
|
||||
content.push(`${subHeaderPrefix}# Workflows Emitting this Event`)
|
||||
content.push(
|
||||
`${subHeaderPrefix}# Workflows Emitting this Event\n\nThe following workflows emit this event when they're executed. These workflows are executed by Medusa's API routes. You can also view the events emitted by API routes in the [Store](https://docs.medusajs.com/api/store) and [Admin](https://docs.medusajs.com/api/admin) API references.`
|
||||
)
|
||||
content.push("")
|
||||
workflows?.forEach((workflow) => {
|
||||
content.push(`- [${workflow}](/references/medusa-workflows/${workflow})`)
|
||||
@@ -188,3 +184,42 @@ function formatEventsType(
|
||||
|
||||
return content.join("\n")
|
||||
}
|
||||
|
||||
function getEventHeading({
|
||||
titleLevel,
|
||||
eventName,
|
||||
payload,
|
||||
deprecated = false,
|
||||
deprecatedMessage,
|
||||
}: {
|
||||
titleLevel: number
|
||||
eventName: string
|
||||
payload: string
|
||||
deprecated?: boolean
|
||||
deprecatedMessage?: string
|
||||
}) {
|
||||
const heading = [eventName]
|
||||
if (deprecated) {
|
||||
if (deprecatedMessage?.length) {
|
||||
heading.push(`<Tooltip text="${deprecatedMessage}">`)
|
||||
}
|
||||
|
||||
heading.push(`<Badge variant="orange">Deprecated</Badge>`)
|
||||
|
||||
if (deprecatedMessage?.length) {
|
||||
heading.push(`</Tooltip>`)
|
||||
}
|
||||
}
|
||||
return `<EventHeader headerLvl="${titleLevel}" headerProps={{ id: "${getEventNameSlug(
|
||||
eventName
|
||||
)}", children: (<>${heading.join(
|
||||
"\n"
|
||||
)}</>), className: "flex flex-wrap justify-center gap-docs_0.25" }} eventName="${eventName}" payload={\`${payload.replaceAll(
|
||||
"`",
|
||||
"\\`"
|
||||
)}\`} />`
|
||||
}
|
||||
|
||||
function getEventNameSlug(eventName: string) {
|
||||
return slugify(eventName.replace(".", ""), { lower: true })
|
||||
}
|
||||
|
||||
+15
-8
@@ -25,6 +25,7 @@ export default function () {
|
||||
str += ` <Table.HeaderCell>\nEvent\n</Table.HeaderCell>\n`
|
||||
str += ` <Table.HeaderCell>\nDescription\n</Table.HeaderCell>\n`
|
||||
str += ` <Table.HeaderCell>\nPayload\n</Table.HeaderCell>\n`
|
||||
str += ` <Table.HeaderCell>\nAction\n</Table.HeaderCell>\n`
|
||||
str += ` </Table.Row>\n`
|
||||
str += ` </Table.Header>\n`
|
||||
str += ` <Table.Body>\n`
|
||||
@@ -33,29 +34,35 @@ export default function () {
|
||||
.map((c) => c.text)
|
||||
.join(" ")
|
||||
.split("--")
|
||||
let eventName = `\`${commentContent[0].trim()}\``
|
||||
const eventName = commentContent[0].trim()
|
||||
const eventPayload = commentContent[2]?.trim() || ""
|
||||
let eventNameFormatted = `\`${eventName}\``
|
||||
const eventDescription = commentContent[1]?.trim() || ""
|
||||
const eventPayload = (commentContent[2]?.trim() || "")
|
||||
const eventPayloadFormatted = eventPayload
|
||||
.replace("```ts\n", "")
|
||||
.replace("\n```", "")
|
||||
const isDeprecated = commentContent.length >= 4
|
||||
|
||||
if (isDeprecated) {
|
||||
const deprecatedText = commentContent[4]?.trim()
|
||||
eventName += `\n`
|
||||
eventNameFormatted += `\n`
|
||||
if (deprecatedText) {
|
||||
eventName += `<Tooltip text="${deprecatedText}">`
|
||||
eventNameFormatted += `<Tooltip text="${deprecatedText}">`
|
||||
}
|
||||
eventName += `<Badge variant="orange">Deprecated</Badge>`
|
||||
eventNameFormatted += `<Badge variant="orange">Deprecated</Badge>`
|
||||
if (deprecatedText) {
|
||||
eventName += `</Tooltip>`
|
||||
eventNameFormatted += `</Tooltip>`
|
||||
}
|
||||
}
|
||||
|
||||
str += ` <Table.Row>\n`
|
||||
str += ` <Table.Cell>\n${eventName}\n</Table.Cell>\n`
|
||||
str += ` <Table.Cell>\n${eventNameFormatted}\n</Table.Cell>\n`
|
||||
str += ` <Table.Cell>\n${eventDescription}\n</Table.Cell>\n`
|
||||
str += ` <Table.Cell>\n\`\`\`ts blockStyle="inline"\n${eventPayload}\n\`\`\`\n</Table.Cell>\n`
|
||||
str += ` <Table.Cell>\n\`\`\`ts blockStyle="inline"\n${eventPayloadFormatted}\n\`\`\`\n</Table.Cell>\n`
|
||||
str += ` <Table.Cell>\n<CopyGeneratedSnippetButton tooltipText="Copy subscriber for event" type="subscriber" options={{
|
||||
event: "${eventName}",
|
||||
payload: \`${eventPayload.replaceAll("`", "\\`")}\`
|
||||
}}/>\n</Table.Cell>\n`
|
||||
str += ` </Table.Row>\n`
|
||||
})
|
||||
str += ` </Table.Body>\n`
|
||||
|
||||
+32
-29
@@ -1868,21 +1868,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@medusajs/icons@npm:2.6.0":
|
||||
version: 2.6.0
|
||||
resolution: "@medusajs/icons@npm:2.6.0"
|
||||
"@medusajs/icons@npm:2.7.1, @medusajs/icons@npm:~2.7.1":
|
||||
version: 2.7.1
|
||||
resolution: "@medusajs/icons@npm:2.7.1"
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
|
||||
checksum: cb8628018398aba010bb7b1f653cb7dc91d9bd59a40f1e7ee4cdc7732559e75062db790fb609fd3f748a9b80ccc0f421267a414ed9f5a7a4e079ef643e65333e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@medusajs/icons@npm:^2.5.1, @medusajs/icons@npm:~2.5.1":
|
||||
version: 2.5.1
|
||||
resolution: "@medusajs/icons@npm:2.5.1"
|
||||
peerDependencies:
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc
|
||||
checksum: f7fbe17475d8c39bd584103ec662f90aa5c8f07159f5820648eba8a0adf42a0d48057518da5a22503e5d5eaca552cbb7b26792613e2ec84827be1bbbafb64201
|
||||
checksum: 6c271671b8ca5d912b14c8f6e91adcd9312e4290b13e9fabe2ad6eb2635051c769fadaa7f2157c90161d8a90f57fd5fb6f8b24b4f86024248414871478f0997c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -1898,11 +1889,23 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@medusajs/ui@npm:4.0.6":
|
||||
version: 4.0.6
|
||||
resolution: "@medusajs/ui@npm:4.0.6"
|
||||
"@medusajs/ui-preset@npm:2.7.1":
|
||||
version: 2.7.1
|
||||
resolution: "@medusajs/ui-preset@npm:2.7.1"
|
||||
dependencies:
|
||||
"@medusajs/icons": ^2.5.1
|
||||
"@tailwindcss/forms": ^0.5.3
|
||||
tailwindcss-animate: ^1.0.6
|
||||
peerDependencies:
|
||||
tailwindcss: ">=3.0.0"
|
||||
checksum: 6b67c5a614e1a8f985cac256c7a363292ca3326ee02a067ec310fec4b3b24b36726e5bc34427b75efb3a395cba2c4e7ba7bd97acc2fb2bb25004570b979e63c0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@medusajs/ui@npm:4.0.9":
|
||||
version: 4.0.9
|
||||
resolution: "@medusajs/ui@npm:4.0.9"
|
||||
dependencies:
|
||||
"@medusajs/icons": 2.7.1
|
||||
"@tanstack/react-table": 8.20.5
|
||||
clsx: ^1.2.1
|
||||
copy-to-clipboard: ^3.3.3
|
||||
@@ -1918,7 +1921,7 @@ __metadata:
|
||||
peerDependencies:
|
||||
react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
|
||||
react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc
|
||||
checksum: ff45b909b3573fd6b443eee0aac47a2f13dbd145ed161e0485f7e22e1e963345e2e38dba236d1b927715feaa79d3dc79671bdeb2075c6f83682dcf8827e6f962
|
||||
checksum: 17f265fa8075cd26f54cda0ef96ffc9afe853fdf10bd42d82ce830f64bc0b932e93f43a9863606a482875fc1f6214a8acb43fd2a6c4fc8f593fa6a4521fbae76
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -6237,8 +6240,8 @@ __metadata:
|
||||
dependencies:
|
||||
"@mdx-js/loader": ^3.1.0
|
||||
"@mdx-js/react": ^3.1.0
|
||||
"@medusajs/icons": 2.6.0
|
||||
"@medusajs/ui": 4.0.6
|
||||
"@medusajs/icons": 2.7.1
|
||||
"@medusajs/ui": 4.0.9
|
||||
"@next/bundle-analyzer": 15.3.1
|
||||
"@next/mdx": 15.3.1
|
||||
"@react-hook/resize-observer": ^2.0.2
|
||||
@@ -6617,7 +6620,7 @@ __metadata:
|
||||
dependencies:
|
||||
"@mdx-js/loader": ^3.1.0
|
||||
"@mdx-js/react": ^3.1.0
|
||||
"@medusajs/icons": ~2.5.1
|
||||
"@medusajs/icons": ~2.7.1
|
||||
"@next/mdx": 15.3.1
|
||||
"@types/mdx": ^2.0.13
|
||||
"@types/node": ^20
|
||||
@@ -7979,8 +7982,8 @@ __metadata:
|
||||
resolution: "docs-ui@workspace:packages/docs-ui"
|
||||
dependencies:
|
||||
"@emotion/is-prop-valid": ^1.3.1
|
||||
"@medusajs/icons": 2.6.0
|
||||
"@medusajs/ui": 4.0.6
|
||||
"@medusajs/icons": 2.7.1
|
||||
"@medusajs/ui": 4.0.9
|
||||
"@next/third-parties": 15.3.1
|
||||
"@octokit/request": ^8.1.1
|
||||
"@react-hook/resize-observer": ^1.2.6
|
||||
@@ -15011,7 +15014,7 @@ __metadata:
|
||||
dependencies:
|
||||
"@mdx-js/loader": ^3.1.0
|
||||
"@mdx-js/react": ^3.1.0
|
||||
"@medusajs/icons": ~2.5.1
|
||||
"@medusajs/icons": ~2.7.1
|
||||
"@next/bundle-analyzer": ^15.1.1
|
||||
"@next/mdx": 15.3.1
|
||||
"@types/mdx": ^2.0.13
|
||||
@@ -16737,7 +16740,7 @@ turbo@latest:
|
||||
version: 0.0.0-use.local
|
||||
resolution: "types@workspace:packages/types"
|
||||
dependencies:
|
||||
"@medusajs/icons": 2.6.0
|
||||
"@medusajs/icons": 2.7.1
|
||||
"@types/node": ^20.11.20
|
||||
openapi-types: ^12.1.3
|
||||
rimraf: ^5.0.5
|
||||
@@ -16826,9 +16829,9 @@ turbo@latest:
|
||||
dependencies:
|
||||
"@faker-js/faker": ^8.0.2
|
||||
"@mdx-js/react": ^3.1.0
|
||||
"@medusajs/icons": 2.6.0
|
||||
"@medusajs/ui": 4.0.6
|
||||
"@medusajs/ui-preset": 2.6.0
|
||||
"@medusajs/icons": 2.7.1
|
||||
"@medusajs/ui": 4.0.9
|
||||
"@medusajs/ui-preset": 2.7.1
|
||||
"@types/node": 20.4.9
|
||||
"@types/react": "npm:types-react@rc"
|
||||
"@types/react-dom": "npm:types-react@rc"
|
||||
@@ -17220,7 +17223,7 @@ turbo@latest:
|
||||
dependencies:
|
||||
"@mdx-js/loader": ^3.1.0
|
||||
"@mdx-js/react": ^3.1.0
|
||||
"@medusajs/icons": ~2.5.1
|
||||
"@medusajs/icons": ~2.7.1
|
||||
"@next/mdx": 15.0.4
|
||||
"@types/mdx": ^2.0.13
|
||||
"@types/node": ^20
|
||||
|
||||
Reference in New Issue
Block a user