feat(inventory,dashboard,types,core-flows,js-sdk,medusa): Improve inventory UX (#10630)
* feat(dashboard): Add UI for bulk editing inventory stock (#10556) * progress * cleanup types * add changeset * fix 0 values * format schema * add delete event and allow copy/pasting enabled for some fields * add response types * add tests * work on fixing setValue behaviour * cleanup toggle logic * add loading state * format schema * add support for bidirectional actions in DataGrid and update Checkbox and RadioGroup * update lock * lint * fix 404 * address feedback * update cursor on bidirectional select
This commit is contained in:
@@ -1,39 +1,35 @@
|
||||
import {
|
||||
AdminCreateInventoryLocationLevelType,
|
||||
AdminUpdateInventoryLocationLevelType,
|
||||
} from "../../../validators"
|
||||
import { MedusaRequest, MedusaResponse } from "@medusajs/framework/http"
|
||||
import { AdminBatchInventoryItemLocationsLevelType } from "../../../validators"
|
||||
|
||||
import { bulkCreateDeleteLevelsWorkflow } from "@medusajs/core-flows"
|
||||
import { BatchMethodRequest } from "@medusajs/framework/types"
|
||||
import { batchInventoryItemLevelsWorkflow } from "@medusajs/core-flows"
|
||||
|
||||
export const POST = async (
|
||||
req: MedusaRequest<
|
||||
BatchMethodRequest<
|
||||
AdminCreateInventoryLocationLevelType,
|
||||
AdminUpdateInventoryLocationLevelType
|
||||
>
|
||||
>,
|
||||
res: MedusaResponse<{ inventory_item: {} }>
|
||||
req: MedusaRequest<AdminBatchInventoryItemLocationsLevelType>,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const { id } = req.params
|
||||
|
||||
// TODO: Normalize workflow and response, and add support for updates
|
||||
const workflow = bulkCreateDeleteLevelsWorkflow(req.scope)
|
||||
await workflow.run({
|
||||
const workflow = batchInventoryItemLevelsWorkflow(req.scope)
|
||||
const output = await workflow.run({
|
||||
input: {
|
||||
deletes:
|
||||
req.validatedBody.delete?.map((location_id) => ({
|
||||
location_id,
|
||||
inventory_item_id: id,
|
||||
})) ?? [],
|
||||
creates:
|
||||
delete: req.validatedBody.delete ?? [],
|
||||
create:
|
||||
req.validatedBody.create?.map((c) => ({
|
||||
...c,
|
||||
inventory_item_id: id,
|
||||
})) ?? [],
|
||||
update:
|
||||
req.validatedBody.update?.map((u) => ({
|
||||
...u,
|
||||
inventory_item_id: id,
|
||||
})) ?? [],
|
||||
force: req.validatedBody.force ?? false,
|
||||
},
|
||||
})
|
||||
|
||||
res.status(200).json({ inventory_item: {} })
|
||||
res.status(200).json({
|
||||
created: output.result.created,
|
||||
updated: output.result.updated,
|
||||
deleted: output.result.deleted,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
import { batchInventoryItemLevelsWorkflow } from "@medusajs/core-flows"
|
||||
import { MedusaRequest, MedusaResponse } from "@medusajs/framework"
|
||||
import { AdminBatchInventoryItemLevelsType } from "../../validators"
|
||||
|
||||
export const POST = async (
|
||||
req: MedusaRequest<AdminBatchInventoryItemLevelsType>,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const body = req.validatedBody
|
||||
|
||||
const output = await batchInventoryItemLevelsWorkflow(req.scope).run({
|
||||
input: body,
|
||||
})
|
||||
|
||||
res.json({
|
||||
created: output.result.created,
|
||||
updated: output.result.updated,
|
||||
deleted: output.result.deleted,
|
||||
})
|
||||
}
|
||||
@@ -4,9 +4,10 @@ import {
|
||||
} from "@medusajs/framework"
|
||||
import { MiddlewareRoute, unlessPath } from "@medusajs/framework/http"
|
||||
import { DEFAULT_BATCH_ENDPOINTS_SIZE_LIMIT } from "../../../utils/middlewares"
|
||||
import { createBatchBody } from "../../utils/validators"
|
||||
import * as QueryConfig from "./query-config"
|
||||
import {
|
||||
AdminBatchInventoryItemLevels,
|
||||
AdminBatchInventoryItemLocationsLevel,
|
||||
AdminCreateInventoryItem,
|
||||
AdminCreateInventoryLocationLevel,
|
||||
AdminGetInventoryItemParams,
|
||||
@@ -49,6 +50,22 @@ export const adminInventoryRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
method: ["POST"],
|
||||
matcher: "/admin/inventory-items/batch",
|
||||
bodyParser: {
|
||||
sizeLimit: DEFAULT_BATCH_ENDPOINTS_SIZE_LIMIT,
|
||||
},
|
||||
middlewares: [validateAndTransformBody(AdminBatchInventoryItemLevels)],
|
||||
},
|
||||
{
|
||||
method: ["POST"],
|
||||
matcher: "/admin/inventory-items/location-levels/batch",
|
||||
bodyParser: {
|
||||
sizeLimit: DEFAULT_BATCH_ENDPOINTS_SIZE_LIMIT,
|
||||
},
|
||||
middlewares: [validateAndTransformBody(AdminBatchInventoryItemLevels)],
|
||||
},
|
||||
{
|
||||
method: ["POST"],
|
||||
matcher: "/admin/inventory-items/:id",
|
||||
@@ -88,12 +105,7 @@ export const adminInventoryRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
sizeLimit: DEFAULT_BATCH_ENDPOINTS_SIZE_LIMIT,
|
||||
},
|
||||
middlewares: [
|
||||
validateAndTransformBody(
|
||||
createBatchBody(
|
||||
AdminCreateInventoryLocationLevel,
|
||||
AdminUpdateInventoryLocationLevel
|
||||
)
|
||||
),
|
||||
validateAndTransformBody(AdminBatchInventoryItemLocationsLevel),
|
||||
validateAndTransformQuery(
|
||||
AdminGetInventoryLocationLevelParams,
|
||||
QueryConfig.retrieveLocationLevelsTransformQueryConfig
|
||||
|
||||
@@ -75,6 +75,30 @@ export const AdminCreateInventoryLocationLevel = z
|
||||
})
|
||||
.strict()
|
||||
|
||||
export type AdminUpdateInventoryLocationLevelBatchType = z.infer<
|
||||
typeof AdminUpdateInventoryLocationLevelBatch
|
||||
>
|
||||
|
||||
export const AdminUpdateInventoryLocationLevelBatch = z
|
||||
.object({
|
||||
id: z.string().optional(),
|
||||
location_id: z.string(),
|
||||
stocked_quantity: z.number().min(0).optional(),
|
||||
incoming_quantity: z.number().min(0).optional(),
|
||||
})
|
||||
.strict()
|
||||
|
||||
export type AdminBatchInventoryItemLocationsLevelType = z.infer<
|
||||
typeof AdminBatchInventoryItemLocationsLevel
|
||||
>
|
||||
|
||||
export const AdminBatchInventoryItemLocationsLevel = z.object({
|
||||
create: z.array(AdminCreateInventoryLocationLevel).optional(),
|
||||
update: z.array(AdminUpdateInventoryLocationLevelBatch).optional(),
|
||||
delete: z.array(z.string()).optional(),
|
||||
force: z.boolean().optional(),
|
||||
})
|
||||
|
||||
export type AdminUpdateInventoryLocationLevelType = z.infer<
|
||||
typeof AdminUpdateInventoryLocationLevel
|
||||
>
|
||||
@@ -129,3 +153,23 @@ export const AdminUpdateInventoryItem = z
|
||||
metadata: z.record(z.unknown()).nullish(),
|
||||
})
|
||||
.strict()
|
||||
|
||||
const AdminBatchInventoryLocationLevel = z.object({
|
||||
inventory_item_id: z.string(),
|
||||
location_id: z.string(),
|
||||
stocked_quantity: z.number().min(0).optional(),
|
||||
incoming_quantity: z.number().min(0).optional(),
|
||||
})
|
||||
|
||||
export const AdminBatchInventoryItemLevels = z
|
||||
.object({
|
||||
create: z.array(AdminBatchInventoryLocationLevel).optional(),
|
||||
update: z.array(AdminBatchInventoryLocationLevel).optional(),
|
||||
delete: z.array(z.string()).optional(),
|
||||
force: z.boolean().optional(),
|
||||
})
|
||||
.strict()
|
||||
|
||||
export type AdminBatchInventoryItemLevelsType = z.infer<
|
||||
typeof AdminBatchInventoryItemLevels
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user