fix(admin-ui): Prevent oversized product request in Price List domain (#5535)

* fix(admin-ui): Prevent oversized product request in Price List domain

* add changeset
This commit is contained in:
Kasper Fabricius Kristensen
2023-11-02 17:05:08 +01:00
committed by GitHub
parent 3bf9d8ddec
commit f7e9829881
7 changed files with 147 additions and 98 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"@medusajs/admin-ui": patch
---
fix(admin-ui): Fix issue were Price List domain would fetch all products on initial load"
@@ -59,11 +59,11 @@ const PriceListEdit = () => {
) )
})} })}
<PriceListGeneralSection <PriceListGeneralSection
key={`${price_list.updated_at}`} key={`gs_${price_list.id}_${price_list.updated_at}`}
priceList={price_list} priceList={price_list}
/> />
<PriceListPricesSection <PriceListPricesSection
key={`${price_list.updated_at}`} key={`ps_${price_list.id}_${price_list.updated_at}`}
priceList={price_list} priceList={price_list}
/> />
{getWidgets("price_list.details.after").map((w, i) => { {getWidgets("price_list.details.after").map((w, i) => {
@@ -9,11 +9,11 @@ import {
Text, Text,
usePrompt, usePrompt,
} from "@medusajs/ui" } from "@medusajs/ui"
import { useAdminCreatePriceListPrices } from "medusa-react"
import * as React from "react" import * as React from "react"
import { useForm } from "react-hook-form" import { useForm } from "react-hook-form"
import * as z from "zod"
import { useAdminCreatePriceListPrices } from "medusa-react"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import * as z from "zod"
import { Form } from "../../../../components/helpers/form" import { Form } from "../../../../components/helpers/form"
import useNotification from "../../../../hooks/use-notification" import useNotification from "../../../../hooks/use-notification"
@@ -621,52 +621,68 @@ const AddProductsModal = ({
productIds={productIds} productIds={productIds}
/> />
</ProgressTabs.Content> </ProgressTabs.Content>
{isLoading ? ( <ProgressTabs.Content
<div className="flex h-full w-full items-center justify-center"> value={Tab.PRICES}
<Spinner className="text-ui-fg-subtle animate-spin" /> className="h-full w-full"
</div> >
) : isError || isNotFound ? ( {isLoading ? (
<div className="flex h-full w-full items-center justify-center"> <div className="flex h-full w-full items-center justify-center">
<div className="text-ui-fg-subtle flex items-center gap-x-2"> <Spinner className="text-ui-fg-subtle animate-spin" />
<ExclamationCircle />
<Text>
{t(
"price-list-add-products-modal-error",
"An error occurred while preparing the form. Reload the page and try again. If the issue persists, try again later."
)}
</Text>
</div> </div>
</div> ) : isError || isNotFound ? (
) : ( <div className="flex h-full w-full items-center justify-center">
<React.Fragment> <div className="text-ui-fg-subtle flex items-center gap-x-2">
<ProgressTabs.Content <ExclamationCircle />
value={Tab.PRICES} <Text>
className="h-full w-full" {t(
> "price-list-add-products-modal-error",
<PriceListPricesForm "An error occurred while preparing the form. Reload the page and try again. If the issue persists, try again later."
setProduct={onSetProduct} )}
form={nestedForm(form, "prices")} </Text>
productIds={selectedIds} </div>
</div>
) : (
<PriceListPricesForm
setProduct={onSetProduct}
form={nestedForm(form, "prices")}
productIds={selectedIds}
/>
)}
</ProgressTabs.Content>
{product && (
<ProgressTabs.Content
value={Tab.EDIT}
className="h-full w-full"
>
{isLoading ? (
<div className="flex h-full w-full items-center justify-center">
<Spinner className="text-ui-fg-subtle animate-spin" />
</div>
) : isError || isNotFound ? (
<div className="flex h-full w-full items-center justify-center">
<div className="text-ui-fg-subtle flex items-center gap-x-2">
<ExclamationCircle />
<Text>
{t(
"price-list-add-products-modal-error",
"An error occurred while preparing the form. Reload the page and try again. If the issue persists, try again later."
)}
</Text>
</div>
</div>
) : (
<PriceListProductPricesForm
product={product}
currencies={currencies}
regions={regions}
control={editControl}
priceListTaxInclusive={priceList.includes_tax}
taxInclEnabled={isTaxInclPricesEnabled}
setValue={setEditValue}
getValues={getEditValues}
/> />
</ProgressTabs.Content>
{product && (
<ProgressTabs.Content
value={Tab.EDIT}
className="h-full w-full"
>
<PriceListProductPricesForm
product={product}
currencies={currencies}
regions={regions}
control={editControl}
priceListTaxInclusive={priceList.includes_tax}
taxInclEnabled={isTaxInclPricesEnabled}
setValue={setEditValue}
getValues={getEditValues}
/>
</ProgressTabs.Content>
)} )}
</React.Fragment> </ProgressTabs.Content>
)} )}
</Form> </Form>
</FocusModal.Body> </FocusModal.Body>
@@ -5,11 +5,11 @@ import { useAdminProducts } from "medusa-react"
import * as React from "react" import * as React from "react"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { Form } from "../../../../components/helpers/form"
import { useDebounce } from "../../../../hooks/use-debounce" import { useDebounce } from "../../../../hooks/use-debounce"
import { NestedForm } from "../../../../utils/nested-form" import { NestedForm } from "../../../../utils/nested-form"
import { ProductFilter, ProductFilterMenu } from "../../components" import { ProductFilter, ProductFilterMenu } from "../../components"
import { PriceListPricesSchema } from "./types" import { PriceListPricesSchema } from "./types"
import { Form } from "../../../../components/helpers/form"
type PriceListPricesFormProps = { type PriceListPricesFormProps = {
form: NestedForm<PriceListPricesSchema> form: NestedForm<PriceListPricesSchema>
@@ -46,13 +46,13 @@ const PriceListPricesForm = ({
{ {
id: productIds, id: productIds,
q: debouncedQuery, q: debouncedQuery,
limit: productIds?.length,
price_list_id: priceListId ? [priceListId] : undefined, price_list_id: priceListId ? [priceListId] : undefined,
...filters, ...filters,
expand: "variants.prices", expand: "variants.prices",
}, },
{ {
keepPreviousData: true, keepPreviousData: true,
enabled: !!productIds?.length,
} }
) )
@@ -5,11 +5,17 @@ import * as React from "react"
type UsePricesFormDataProps = { type UsePricesFormDataProps = {
priceList?: PriceList priceList?: PriceList
productIds: string[] productIds: string[]
enable?: {
products?: boolean
}
} }
const usePricesFormData = ({ const usePricesFormData = ({
priceList, priceList,
productIds, productIds,
enable = {
products: true,
},
}: UsePricesFormDataProps) => { }: UsePricesFormDataProps) => {
const { const {
products, products,
@@ -18,11 +24,11 @@ const usePricesFormData = ({
} = useAdminProducts( } = useAdminProducts(
{ {
id: productIds, id: productIds,
limit: productIds?.length,
price_list_id: priceList ? [priceList.id] : undefined, price_list_id: priceList ? [priceList.id] : undefined,
}, },
{ {
keepPreviousData: true, keepPreviousData: true,
enabled: !!productIds?.length && enable.products,
} }
) )
@@ -53,9 +59,11 @@ const usePricesFormData = ({
} }
) )
const isLoading = isLoadingProducts || isLoadingStore || isLoadingRegions const isLoading =
const isError = isErrorProducts || isStoreError || isErrorRegions (enable.products && isLoadingProducts) || isLoadingStore || isLoadingRegions
const isNotFound = !products || !regions || !currencies const isError =
(enable.products && isErrorProducts) || isStoreError || isErrorRegions
const isNotFound = (enable.products && !products) || !regions || !currencies
return { return {
isError, isError,
@@ -280,7 +280,7 @@ const PriceListProductsForm = ({
const { products, count, isLoading, isError } = useAdminProducts( const { products, count, isLoading, isError } = useAdminProducts(
{ {
limit: PAGE_SIZE, limit: 20,
offset, offset,
expand: "variants,sales_channels,collection", expand: "variants,sales_channels,collection",
q: debouncedQuery, q: debouncedQuery,
@@ -11,7 +11,6 @@ import * as React from "react"
import { useForm, useWatch } from "react-hook-form" import { useForm, useWatch } from "react-hook-form"
import * as z from "zod" import * as z from "zod"
import { ExclamationCircle, Spinner } from "@medusajs/icons"
import { Product } from "@medusajs/medusa" import { Product } from "@medusajs/medusa"
import { useAdminCreatePriceList } from "medusa-react" import { useAdminCreatePriceList } from "medusa-react"
import { Form } from "../../../components/helpers/form" import { Form } from "../../../components/helpers/form"
@@ -41,6 +40,7 @@ import {
type PriceListProductPricesSchema, type PriceListProductPricesSchema,
} from "../forms/price-list-product-prices-form" } from "../forms/price-list-product-prices-form"
import { ExclamationCircle, Spinner } from "@medusajs/icons"
import { useTranslation } from "react-i18next" import { useTranslation } from "react-i18next"
import { import {
PriceListProductsForm, PriceListProductsForm,
@@ -159,6 +159,9 @@ const PriceListNew = () => {
const { isLoading, isError, isNotFound, regions, currencies } = const { isLoading, isError, isNotFound, regions, currencies } =
usePricesFormData({ usePricesFormData({
productIds: selectedIds, productIds: selectedIds,
enable: {
products: false,
},
}) })
const onCloseModal = React.useCallback(() => { const onCloseModal = React.useCallback(() => {
@@ -690,52 +693,69 @@ const PriceListNew = () => {
> >
<PriceListProductsForm form={nestedForm(form, "products")} /> <PriceListProductsForm form={nestedForm(form, "products")} />
</ProgressTabs.Content> </ProgressTabs.Content>
{isLoading ? (
<div className="flex h-full w-full items-center justify-center"> <ProgressTabs.Content
<Spinner className="text-ui-fg-subtle animate-spin" /> value={Tab.PRICES}
</div> className="h-full w-full"
) : isError || isNotFound ? ( >
<div className="flex h-full w-full items-center justify-center"> {isLoading ? (
<div className="text-ui-fg-subtle flex items-center gap-x-2"> <div className="flex h-full w-full items-center justify-center">
<ExclamationCircle /> <Spinner className="text-ui-fg-subtle animate-spin" />
<Text>
{t(
"price-list-new-form-error-loading-products",
"An error occurred while preparing the form. Reload the page and try again. If the issue persists, try again later."
)}
</Text>
</div> </div>
</div> ) : isError || isNotFound ? (
) : ( <div className="flex h-full w-full items-center justify-center">
<React.Fragment> <div className="text-ui-fg-subtle flex items-center gap-x-2">
<ProgressTabs.Content <ExclamationCircle />
value={Tab.PRICES} <Text>
className="h-full w-full" {t(
> "price-list-new-form-error-loading-products",
<PriceListPricesForm "An error occurred while preparing the form. Reload the page and try again. If the issue persists, try again later."
setProduct={onSetProduct} )}
form={nestedForm(form, "prices")} </Text>
productIds={selectedIds} </div>
</div>
) : (
<PriceListPricesForm
setProduct={onSetProduct}
form={nestedForm(form, "prices")}
productIds={selectedIds}
/>
)}
</ProgressTabs.Content>
{product && (
<ProgressTabs.Content
value={Tab.EDIT}
className="h-full w-full"
>
{isLoading ? (
<div className="flex h-full w-full items-center justify-center">
<Spinner className="text-ui-fg-subtle animate-spin" />
</div>
) : isError || isNotFound ? (
<div className="flex h-full w-full items-center justify-center">
<div className="text-ui-fg-subtle flex items-center gap-x-2">
<ExclamationCircle />
<Text>
{t(
"price-list-new-form-error-loading-products",
"An error occurred while preparing the form. Reload the page and try again. If the issue persists, try again later."
)}
</Text>
</div>
</div>
) : (
<PriceListProductPricesForm
priceListTaxInclusive={taxToggleState}
taxInclEnabled={isTaxInclPricesEnabled}
product={product}
currencies={currencies}
regions={regions}
control={editControl}
getValues={getEditValues}
setValue={setEditValue}
/> />
</ProgressTabs.Content>
{product && (
<ProgressTabs.Content
value={Tab.EDIT}
className="h-full w-full"
>
<PriceListProductPricesForm
priceListTaxInclusive={taxToggleState}
taxInclEnabled={isTaxInclPricesEnabled}
product={product}
currencies={currencies}
regions={regions}
control={editControl}
getValues={getEditValues}
setValue={setEditValue}
/>
</ProgressTabs.Content>
)} )}
</React.Fragment> </ProgressTabs.Content>
)} )}
</Form> </Form>
</FocusModal.Body> </FocusModal.Body>