Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Input, Label, Select, Button } from "@medusajs/ui"
import { Label, Select, Button } from "@medusajs/ui"
import { useAvailableEvents } from "../../../../hooks/api/available-events"
import { OPERATOR_TYPES } from "../../../../modules/mpn-automation/types/types"
import { Controller, useFieldArray } from "react-hook-form"
import { useMemo } from "react"
import { Trash, Plus } from "@medusajs/icons"
import { RuleValueInput } from "./rule-value-input"

export function AutomationsRulesForm({
form,
Expand Down Expand Up @@ -163,27 +164,10 @@ export function AutomationsRulesForm({
</>
)}
/>
<Controller
name={`rules.items.${index}.rule_values.0.value`}
<RuleValueInput
control={form.control}
render={({ field, fieldState }) => (
<>
<Label>Value</Label>
<Input
value={field.value ?? ""}
onChange={(e) => {
field.onChange(e.target.value)
}}
onBlur={field.onBlur}
ref={field.ref}
/>
{fieldState.error && (
<span className="text-red-500 text-sm">
{fieldState.error.message}
</span>
)}
</>
)}
name={`rules.items.${index}.rule_values.0.value`}
operator={form.watch(`rules.items.${index}.operator`)}
/>
</div>
<Button
Expand All @@ -205,7 +189,7 @@ export function AutomationsRulesForm({
className="w-full"
>
<Plus />
Add Item
Add condition
</Button>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { RuleValueInput } from "./rule-value-input"

Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { Input, Label } from "@medusajs/ui"
import { Controller, Control } from "react-hook-form"
import { OperatorType } from "../../../../../modules/mpn-automation/types/types"
import { ChipInput } from "../../../../components/inputs/chip-input"

type RuleValueInputProps = {
control: Control<any>
name: string
operator: string
}

export function RuleValueInput({
control,
name,
operator,
}: RuleValueInputProps) {
const arrayOperators = [
OperatorType.IN,
OperatorType.NOT_IN,
OperatorType.CONTAINS,
OperatorType.NOT_CONTAINS,
]

const noValueOperators = [
OperatorType.EMPTY,
OperatorType.NOT_EMPTY,
]

const isArrayOperator = arrayOperators.includes(operator as OperatorType)
const isNoValueOperator = noValueOperators.includes(operator as OperatorType)

if (isNoValueOperator) {
return null
}

return (
<Controller
name={name}
control={control}
render={({ field, fieldState }) => {
if (isArrayOperator) {
const arrayValue = Array.isArray(field.value)
? field.value
: field.value
? [String(field.value)]
: []

return (
<>
<Label>Values</Label>
<ChipInput
value={arrayValue}
onChange={(values) => field.onChange(values)}
onBlur={field.onBlur}
placeholder="Add values (press Enter or comma)"
allowDuplicates={false}
/>
{fieldState.error && (
<span className="text-red-500 text-sm">
{fieldState.error.message}
</span>
)}
</>
)
}

const stringValue = Array.isArray(field.value)
? field.value[0] || ""
: field.value ?? ""

return (
<>
<Label>Value</Label>
<Input
value={stringValue}
onChange={(e) => field.onChange(e.target.value)}
onBlur={field.onBlur}
ref={field.ref}
placeholder="Enter value"
/>
{fieldState.error && (
<span className="text-red-500 text-sm">
{fieldState.error.message}
</span>
)}
</>
)
}}
/>
)
}

18 changes: 16 additions & 2 deletions src/admin/automations/automations-form/types/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,23 @@ export const baseAutomationFormSchema = z.object({
.array(
z.object({
id: z.string().optional(),
// Value can be string, number, array, or null (for empty/not_empty operators)
value: z
.string()
.min(1, "Value is required"),
.union([
z.string().min(1, "Value is required"),
z.number(),
z.array(
z
.string()
.min(
1,
"Array values cannot be empty"
)
),
z.array(z.number()),
z.null(),
])
.optional(),
})
)
.optional(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { baseAutomationFormSchema } from "../types"
import { z } from "zod"
import { baseAutomationFormSchema } from "../types"

// Function to create schema with dynamic validation based on availableActions
export function createAutomationFormSchema(
Expand Down
11 changes: 10 additions & 1 deletion src/api/admin/mpn/automations/rules/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,16 @@ export const PostAutomationRulesSchema = z.object({
.array(
z.object({
id: z.string().optional(),
value: z.string().nullable().optional(),
// Value can be string, number, or array (for array operators like contains, in, etc.)
value: z
.union([
z.string(),
z.number(),
z.array(z.string()),
z.array(z.number()),
])
.nullable()
.optional(),
metadata: z
.record(z.any())
.nullable()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -473,12 +473,12 @@
},
"value": {
"name": "value",
"type": "text",
"type": "jsonb",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "text"
"mappedType": "json"
},
"metadata": {
"name": "metadata",
Expand Down
13 changes: 13 additions & 0 deletions src/modules/mpn-automation/migrations/Migration20251217190839.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Migration } from '@mikro-orm/migrations';

export class Migration20251217190839 extends Migration {

override async up(): Promise<void> {
this.addSql(`alter table if exists "mpn_automation_rule_value" alter column "value" type jsonb using ("value"::jsonb);`);
}

override async down(): Promise<void> {
this.addSql(`alter table if exists "mpn_automation_rule_value" alter column "value" type text using ("value"::text);`);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ export const MpnAutomationRuleValue = model.define(
{
id: model.id().primaryKey(),

value: model.text().nullable(),
// Value can be string, number, or array (for array operators like contains)
value: model.json().nullable(),

metadata: model.json().nullable(),

Expand Down
3 changes: 2 additions & 1 deletion src/modules/mpn-automation/types/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import { TriggerType } from "./types"

export interface AutomationRuleValue {
id?: string
value: string | null
// Value can be string, number, or array (for array operators like contains, in, etc.)
value: string | number | string[] | number[] | null
metadata: Record<string, any> | null
}

Expand Down
38 changes: 34 additions & 4 deletions src/modules/mpn-automation/types/modules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import {
} from "./inventory"
import { PRODUCT_ATTRIBUTES } from "./product"
import { PRODUCT_VARIANT_ATTRIBUTES } from "./product-variant"
import { PRODUCT_TAG_ATTRIBUTES } from "./product-tag"
import { PRODUCT_TYPE_ATTRIBUTES } from "./product-type"
import { PRODUCT_CATEGORY_ATTRIBUTES } from "./product-category"
import { Attribute } from "../types"

/**
Expand Down Expand Up @@ -91,6 +94,15 @@ const EVENT_METADATA_REGISTRY: Record<
},
],
},
"product.updated": {
attributes: PRODUCT_ATTRIBUTES,
templates: [
{
value: "product",
name: "Product",
},
],
},
"product-variant.updated": {
attributes: PRODUCT_VARIANT_ATTRIBUTES,
templates: [
Expand All @@ -100,12 +112,30 @@ const EVENT_METADATA_REGISTRY: Record<
},
],
},
"product.updated": {
attributes: PRODUCT_ATTRIBUTES,
"product-tag.updated": {
attributes: PRODUCT_TAG_ATTRIBUTES,
templates: [
{
value: "product",
name: "Product",
value: "product-tag",
name: "Product Tag",
},
],
},
"product-type.updated": {
attributes: PRODUCT_TYPE_ATTRIBUTES,
templates: [
{
value: "product-type",
name: "Product Type",
},
],
},
"product-category.updated": {
attributes: PRODUCT_CATEGORY_ATTRIBUTES,
templates: [
{
value: "product-category",
name: "Product Category",
},
],
},
Expand Down
14 changes: 14 additions & 0 deletions src/modules/mpn-automation/types/modules/inventory/inventory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,18 @@ export const INVENTORY_LEVEL_ATTRIBUTES = [
value: "inventory_level.location_id",
label: "Location ID",
},
{
value: "inventory_level.stock_locations.id",
label: "Stock Location ID",
type: "array",
isRelation: true,
relationType: "stock_locations",
},
{
value: "inventory_level.stock_locations.name",
label: "Stock Location Name",
type: "array",
isRelation: true,
relationType: "stock_locations",
}
]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./product-category"
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
export const PRODUCT_CATEGORY_ATTRIBUTES = [
{
value: "product_category.id",
label: "ID",
},
{
value: "product_category.name",
label: "Name",
},
{
value: "product_category.description",
label: "Description",
},
{
value: "product_category.handle",
label: "Handle",
},
{
value: "product_category.is_active",
label: "Is Active",
},
{
value: "product_category.is_internal",
label: "Is Internal",
},
{
value: "product_category.rank",
label: "Rank",
},
{
value: "product_category.parent_category_id",
label: "Parent Category ID",
},
{
value: "product_category.created_at",
label: "Created At",
},
{
value: "product_category.updated_at",
label: "Updated At",
},
]

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./product-tag"
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export const PRODUCT_TAG_ATTRIBUTES = [
{
value: "product_tag.id",
label: "ID",
},
{
value: "product_tag.value",
label: "Value",
},
{
value: "product_tag.created_at",
label: "Created At",
},
{
value: "product_tag.updated_at",
label: "Updated At",
},
]
Loading