@csbeker/medusa-product-attributes 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (237) hide show
  1. package/.medusa/server/src/admin/index.js +9012 -0
  2. package/.medusa/server/src/admin/index.mjs +9010 -0
  3. package/.medusa/server/src/api/admin/middlewares.js +10 -0
  4. package/.medusa/server/src/api/admin/plugin/attribute-set/[id]/attributes/route.js +17 -0
  5. package/.medusa/server/src/api/admin/plugin/attribute-set/[id]/route.js +33 -0
  6. package/.medusa/server/src/api/admin/plugin/attribute-set/middlewares.js +44 -0
  7. package/.medusa/server/src/api/admin/plugin/attribute-set/query-config.js +22 -0
  8. package/.medusa/server/src/api/admin/plugin/attribute-set/route.js +25 -0
  9. package/.medusa/server/src/api/admin/plugin/attribute-set/validators.js +37 -0
  10. package/.medusa/server/src/api/admin/plugin/attributes/[id]/route.js +68 -0
  11. package/.medusa/server/src/api/admin/plugin/attributes/[id]/values/[valueId]/route.js +37 -0
  12. package/.medusa/server/src/api/admin/plugin/attributes/[id]/values/route.js +31 -0
  13. package/.medusa/server/src/api/admin/plugin/attributes/middlewares.js +103 -0
  14. package/.medusa/server/src/api/admin/plugin/attributes/query-config.js +41 -0
  15. package/.medusa/server/src/api/admin/plugin/attributes/route.js +28 -0
  16. package/.medusa/server/src/api/admin/plugin/attributes/validators.js +69 -0
  17. package/.medusa/server/src/api/admin/plugin/route.js +7 -0
  18. package/.medusa/server/src/api/middlewares.js +12 -0
  19. package/.medusa/server/src/api/store/middlewares.js +8 -0
  20. package/.medusa/server/src/api/store/plugin/attributes/middlewares.js +64 -0
  21. package/.medusa/server/src/api/store/plugin/attributes/products/middlewares.js +100 -0
  22. package/.medusa/server/src/api/store/plugin/attributes/products/query-config.js +20 -0
  23. package/.medusa/server/src/api/store/plugin/attributes/products/route.js +48 -0
  24. package/.medusa/server/src/api/store/plugin/attributes/products/validators.js +39 -0
  25. package/.medusa/server/src/api/store/plugin/attributes/query-config.js +21 -0
  26. package/.medusa/server/src/api/store/plugin/attributes/route.js +15 -0
  27. package/.medusa/server/src/api/store/plugin/attributes/validators.js +14 -0
  28. package/.medusa/server/src/api/store/plugin/route.js +7 -0
  29. package/.medusa/server/src/api/utils/common-validators.js +23 -0
  30. package/.medusa/server/src/api/utils/constants.js +6 -0
  31. package/.medusa/server/src/api/utils/middlewares.js +34 -0
  32. package/.medusa/server/src/links/attribute-product-category.js +16 -0
  33. package/.medusa/server/src/links/attribute-value-product.js +16 -0
  34. package/.medusa/server/src/modules/attribute/events/index.js +8 -0
  35. package/.medusa/server/src/modules/attribute/index.js +13 -0
  36. package/.medusa/server/src/modules/attribute/migrations/Migration20250319161229.js +24 -0
  37. package/.medusa/server/src/modules/attribute/migrations/Migration20250320182643.js +16 -0
  38. package/.medusa/server/src/modules/attribute/migrations/Migration20250321162638.js +14 -0
  39. package/.medusa/server/src/modules/attribute/migrations/Migration20250505144933.js +23 -0
  40. package/.medusa/server/src/modules/attribute/migrations/Migration20250505201747.js +21 -0
  41. package/.medusa/server/src/modules/attribute/migrations/Migration20250506162300.js +14 -0
  42. package/.medusa/server/src/modules/attribute/migrations/Migration20250611160552.js +14 -0
  43. package/.medusa/server/src/modules/attribute/migrations/Migration20250611173345.js +16 -0
  44. package/.medusa/server/src/modules/attribute/migrations/Migration20250612192857.js +16 -0
  45. package/.medusa/server/src/modules/attribute/models/attribute-possible-value.js +24 -0
  46. package/.medusa/server/src/modules/attribute/models/attribute-set.js +22 -0
  47. package/.medusa/server/src/modules/attribute/models/attribute-value.js +17 -0
  48. package/.medusa/server/src/modules/attribute/models/attribute.js +27 -0
  49. package/.medusa/server/src/modules/attribute/service.js +84 -0
  50. package/.medusa/server/src/modules/attribute/types/attribute/common.js +13 -0
  51. package/.medusa/server/src/modules/attribute/types/attribute/index.js +18 -0
  52. package/.medusa/server/src/modules/attribute/types/attribute-set/index.js +18 -0
  53. package/.medusa/server/src/modules/attribute/types/attribute-set/mutations.js +3 -0
  54. package/.medusa/server/src/modules/attribute/types/attribute-value/index.js +18 -0
  55. package/.medusa/server/src/modules/attribute/types/attribute-value/mutations.js +3 -0
  56. package/.medusa/server/src/modules/attribute/types/index.js +20 -0
  57. package/.medusa/server/src/types/attribute/common.js +3 -0
  58. package/.medusa/server/src/types/attribute/http/attribute/admin/index.js +3 -0
  59. package/.medusa/server/src/types/attribute/http/attribute/index.js +18 -0
  60. package/.medusa/server/src/types/attribute/http/attribute-set/index.js +3 -0
  61. package/.medusa/server/src/types/attribute/http/index.js +19 -0
  62. package/.medusa/server/src/types/attribute/index.js +19 -0
  63. package/.medusa/server/src/utils/index.js +18 -0
  64. package/.medusa/server/src/utils/products-created-handler.js +22 -0
  65. package/.medusa/server/src/utils/products-updated-handler.js +58 -0
  66. package/.medusa/server/src/utils/validate-attribute-values-to-link.js +43 -0
  67. package/.medusa/server/src/workflows/attribute/index.js +19 -0
  68. package/.medusa/server/src/workflows/attribute/steps/create-attribute-possible-values.js +18 -0
  69. package/.medusa/server/src/workflows/attribute/steps/create-attributes.js +27 -0
  70. package/.medusa/server/src/workflows/attribute/steps/delete-attribute.js +31 -0
  71. package/.medusa/server/src/workflows/attribute/steps/index.js +21 -0
  72. package/.medusa/server/src/workflows/attribute/steps/update-attributes.js +34 -0
  73. package/.medusa/server/src/workflows/attribute/workflows/create-attribute-possible-values.js +11 -0
  74. package/.medusa/server/src/workflows/attribute/workflows/create-attributes.js +46 -0
  75. package/.medusa/server/src/workflows/attribute/workflows/delete-attribute.js +10 -0
  76. package/.medusa/server/src/workflows/attribute/workflows/index.js +20 -0
  77. package/.medusa/server/src/workflows/attribute/workflows/update-attributes.js +73 -0
  78. package/.medusa/server/src/workflows/attribute-set/steps/batch-link-attribute-set-attributes.js +66 -0
  79. package/.medusa/server/src/workflows/attribute-set/steps/create-attribute-set.js +24 -0
  80. package/.medusa/server/src/workflows/attribute-set/steps/index.js +20 -0
  81. package/.medusa/server/src/workflows/attribute-set/steps/update-attribute-set.js +22 -0
  82. package/.medusa/server/src/workflows/attribute-set/workflows/batch-link-attribute-set-attributes.js +10 -0
  83. package/.medusa/server/src/workflows/attribute-set/workflows/create-attribute-set.js +11 -0
  84. package/.medusa/server/src/workflows/attribute-set/workflows/index.js +20 -0
  85. package/.medusa/server/src/workflows/attribute-set/workflows/update-attribute-set.js +10 -0
  86. package/.medusa/server/src/workflows/attribute-value/steps/create-attribute-value.js +18 -0
  87. package/.medusa/server/src/workflows/attribute-value/steps/delete-attribute-value.js +18 -0
  88. package/.medusa/server/src/workflows/attribute-value/steps/index.js +20 -0
  89. package/.medusa/server/src/workflows/attribute-value/steps/validate-attribute-value.js +53 -0
  90. package/.medusa/server/src/workflows/attribute-value/workflow/create-attribute-value.js +28 -0
  91. package/.medusa/server/src/workflows/attribute-value/workflow/delete-attribute-value.js +38 -0
  92. package/.medusa/server/src/workflows/attribute-value/workflow/index.js +19 -0
  93. package/.medusa/server/src/workflows/attribute_possible_value/index.js +19 -0
  94. package/.medusa/server/src/workflows/attribute_possible_value/steps/index.js +18 -0
  95. package/.medusa/server/src/workflows/attribute_possible_value/steps/update-attribute-possible-value.js +18 -0
  96. package/.medusa/server/src/workflows/attribute_possible_value/workflows/index.js +18 -0
  97. package/.medusa/server/src/workflows/attribute_possible_value/workflows/update-attribute-possible-value.js +11 -0
  98. package/.medusa/server/src/workflows/index.js +18 -0
  99. package/CHANGELOG.md +104 -0
  100. package/README.md +86 -0
  101. package/package.json +90 -0
  102. package/src/admin/README.md +31 -0
  103. package/src/admin/components/metadata-editor/index.tsx +101 -0
  104. package/src/admin/components/section-row.tsx +41 -0
  105. package/src/admin/hooks/api/attribute-set.ts +122 -0
  106. package/src/admin/hooks/api/attributes.ts +126 -0
  107. package/src/admin/hooks/table/columns/index.ts +1 -0
  108. package/src/admin/hooks/table/columns/use-attribute-table-columns.tsx +280 -0
  109. package/src/admin/layouts/single-column.tsx +11 -0
  110. package/src/admin/lib/config.ts +8 -0
  111. package/src/admin/lib/query-key-factory.ts +53 -0
  112. package/src/admin/routes/attributes/[id]/edit/page.tsx +133 -0
  113. package/src/admin/routes/attributes/[id]/edit-possible-value/page.tsx +174 -0
  114. package/src/admin/routes/attributes/[id]/page.tsx +127 -0
  115. package/src/admin/routes/attributes/components/AttributeForm.tsx +301 -0
  116. package/src/admin/routes/attributes/components/AttributeSetTable.tsx +108 -0
  117. package/src/admin/routes/attributes/components/category-selection-modal.tsx +82 -0
  118. package/src/admin/routes/attributes/components/possible-values-table.tsx +119 -0
  119. package/src/admin/routes/attributes/create/components/MultiSelectCategory.tsx +148 -0
  120. package/src/admin/routes/attributes/create/components/PossibleValuesList.tsx +151 -0
  121. package/src/admin/routes/attributes/create/page.tsx +123 -0
  122. package/src/admin/routes/attributes/create-set/page.tsx +110 -0
  123. package/src/admin/routes/attributes/page.tsx +346 -0
  124. package/src/admin/routes/attributes/set/[id]/attributes/page.tsx +35 -0
  125. package/src/admin/routes/attributes/set/[id]/components/AttributeSetAttributesSection.tsx +114 -0
  126. package/src/admin/routes/attributes/set/[id]/components/AttributeSetGeneralSection.tsx +42 -0
  127. package/src/admin/routes/attributes/set/[id]/components/attribute-set-attributes-form.tsx +143 -0
  128. package/src/admin/routes/attributes/set/[id]/components/index.ts +2 -0
  129. package/src/admin/routes/attributes/set/[id]/edit/page.tsx +119 -0
  130. package/src/admin/routes/attributes/set/[id]/page.tsx +45 -0
  131. package/src/admin/tsconfig.json +27 -0
  132. package/src/admin/types/global.d.ts +3 -0
  133. package/src/admin/vite-env.d.ts +1 -0
  134. package/src/api/README.md +133 -0
  135. package/src/api/admin/middlewares.ts +8 -0
  136. package/src/api/admin/plugin/attribute-set/[id]/attributes/route.ts +17 -0
  137. package/src/api/admin/plugin/attribute-set/[id]/route.ts +41 -0
  138. package/src/api/admin/plugin/attribute-set/middlewares.ts +42 -0
  139. package/src/api/admin/plugin/attribute-set/query-config.ts +20 -0
  140. package/src/api/admin/plugin/attribute-set/route.ts +34 -0
  141. package/src/api/admin/plugin/attribute-set/validators.ts +45 -0
  142. package/src/api/admin/plugin/attributes/[id]/route.ts +85 -0
  143. package/src/api/admin/plugin/attributes/[id]/values/[valueId]/route.ts +41 -0
  144. package/src/api/admin/plugin/attributes/[id]/values/route.ts +39 -0
  145. package/src/api/admin/plugin/attributes/middlewares.ts +91 -0
  146. package/src/api/admin/plugin/attributes/query-config.ts +42 -0
  147. package/src/api/admin/plugin/attributes/route.ts +33 -0
  148. package/src/api/admin/plugin/attributes/validators.ts +91 -0
  149. package/src/api/admin/plugin/route.ts +8 -0
  150. package/src/api/middlewares.ts +10 -0
  151. package/src/api/store/middlewares.ts +6 -0
  152. package/src/api/store/plugin/attributes/middlewares.ts +33 -0
  153. package/src/api/store/plugin/attributes/products/middlewares.ts +73 -0
  154. package/src/api/store/plugin/attributes/products/query-config.ts +19 -0
  155. package/src/api/store/plugin/attributes/products/route.ts +68 -0
  156. package/src/api/store/plugin/attributes/products/validators.ts +55 -0
  157. package/src/api/store/plugin/attributes/query-config.ts +19 -0
  158. package/src/api/store/plugin/attributes/route.ts +13 -0
  159. package/src/api/store/plugin/attributes/validators.ts +14 -0
  160. package/src/api/store/plugin/route.ts +8 -0
  161. package/src/api/utils/common-validators.ts +24 -0
  162. package/src/api/utils/constants.ts +2 -0
  163. package/src/api/utils/middlewares.ts +31 -0
  164. package/src/jobs/README.md +36 -0
  165. package/src/links/README.md +26 -0
  166. package/src/links/attribute-product-category.ts +14 -0
  167. package/src/links/attribute-value-product.ts +14 -0
  168. package/src/modules/README.md +116 -0
  169. package/src/modules/attribute/events/index.ts +4 -0
  170. package/src/modules/attribute/index.ts +8 -0
  171. package/src/modules/attribute/migrations/.snapshot-medusa-attribute.json +624 -0
  172. package/src/modules/attribute/migrations/Migration20250319161229.ts +27 -0
  173. package/src/modules/attribute/migrations/Migration20250320182643.ts +15 -0
  174. package/src/modules/attribute/migrations/Migration20250321162638.ts +13 -0
  175. package/src/modules/attribute/migrations/Migration20250505144933.ts +26 -0
  176. package/src/modules/attribute/migrations/Migration20250505201747.ts +23 -0
  177. package/src/modules/attribute/migrations/Migration20250506162300.ts +13 -0
  178. package/src/modules/attribute/migrations/Migration20250611160552.ts +13 -0
  179. package/src/modules/attribute/migrations/Migration20250611173345.ts +17 -0
  180. package/src/modules/attribute/migrations/Migration20250612192857.ts +17 -0
  181. package/src/modules/attribute/models/attribute-possible-value.ts +20 -0
  182. package/src/modules/attribute/models/attribute-set.ts +18 -0
  183. package/src/modules/attribute/models/attribute-value.ts +13 -0
  184. package/src/modules/attribute/models/attribute.ts +23 -0
  185. package/src/modules/attribute/service.ts +102 -0
  186. package/src/modules/attribute/types/attribute/common.ts +94 -0
  187. package/src/modules/attribute/types/attribute/index.ts +1 -0
  188. package/src/modules/attribute/types/attribute-set/index.ts +1 -0
  189. package/src/modules/attribute/types/attribute-set/mutations.ts +7 -0
  190. package/src/modules/attribute/types/attribute-value/index.ts +1 -0
  191. package/src/modules/attribute/types/attribute-value/mutations.ts +5 -0
  192. package/src/modules/attribute/types/index.ts +3 -0
  193. package/src/providers/README.md +30 -0
  194. package/src/subscribers/README.md +59 -0
  195. package/src/types/attribute/common.ts +173 -0
  196. package/src/types/attribute/http/attribute/admin/index.ts +0 -0
  197. package/src/types/attribute/http/attribute/index.ts +42 -0
  198. package/src/types/attribute/http/attribute-set/index.ts +10 -0
  199. package/src/types/attribute/http/index.ts +2 -0
  200. package/src/types/attribute/index.ts +2 -0
  201. package/src/utils/index.ts +1 -0
  202. package/src/utils/products-created-handler.ts +35 -0
  203. package/src/utils/products-updated-handler.ts +74 -0
  204. package/src/utils/validate-attribute-values-to-link.ts +67 -0
  205. package/src/workflows/README.md +79 -0
  206. package/src/workflows/attribute/index.ts +2 -0
  207. package/src/workflows/attribute/steps/create-attribute-possible-values.ts +29 -0
  208. package/src/workflows/attribute/steps/create-attributes.ts +35 -0
  209. package/src/workflows/attribute/steps/delete-attribute.ts +41 -0
  210. package/src/workflows/attribute/steps/index.ts +4 -0
  211. package/src/workflows/attribute/steps/update-attributes.ts +45 -0
  212. package/src/workflows/attribute/workflows/create-attribute-possible-values.ts +17 -0
  213. package/src/workflows/attribute/workflows/create-attributes.ts +56 -0
  214. package/src/workflows/attribute/workflows/delete-attribute.ts +15 -0
  215. package/src/workflows/attribute/workflows/index.ts +3 -0
  216. package/src/workflows/attribute/workflows/update-attributes.ts +103 -0
  217. package/src/workflows/attribute-set/steps/batch-link-attribute-set-attributes.ts +82 -0
  218. package/src/workflows/attribute-set/steps/create-attribute-set.ts +34 -0
  219. package/src/workflows/attribute-set/steps/index.ts +3 -0
  220. package/src/workflows/attribute-set/steps/update-attribute-set.ts +32 -0
  221. package/src/workflows/attribute-set/workflows/batch-link-attribute-set-attributes.ts +12 -0
  222. package/src/workflows/attribute-set/workflows/create-attribute-set.ts +17 -0
  223. package/src/workflows/attribute-set/workflows/index.ts +3 -0
  224. package/src/workflows/attribute-set/workflows/update-attribute-set.ts +14 -0
  225. package/src/workflows/attribute-value/steps/create-attribute-value.ts +26 -0
  226. package/src/workflows/attribute-value/steps/delete-attribute-value.ts +26 -0
  227. package/src/workflows/attribute-value/steps/index.ts +3 -0
  228. package/src/workflows/attribute-value/steps/validate-attribute-value.ts +95 -0
  229. package/src/workflows/attribute-value/workflow/create-attribute-value.ts +36 -0
  230. package/src/workflows/attribute-value/workflow/delete-attribute-value.ts +46 -0
  231. package/src/workflows/attribute-value/workflow/index.ts +2 -0
  232. package/src/workflows/attribute_possible_value/index.ts +2 -0
  233. package/src/workflows/attribute_possible_value/steps/index.ts +1 -0
  234. package/src/workflows/attribute_possible_value/steps/update-attribute-possible-value.ts +25 -0
  235. package/src/workflows/attribute_possible_value/workflows/index.ts +1 -0
  236. package/src/workflows/attribute_possible_value/workflows/update-attribute-possible-value.ts +15 -0
  237. package/src/workflows/index.ts +1 -0
@@ -0,0 +1,119 @@
1
+ import { defineRouteConfig } from "@medusajs/admin-sdk";
2
+ import { AttributeSet } from "../../../../../../types/attribute";
3
+ import { useForm } from "react-hook-form";
4
+ import { zodResolver } from "@hookform/resolvers/zod";
5
+ import {
6
+ useAttributeSet,
7
+ useUpdateAttributeSet,
8
+ } from "../../../../../hooks/api/attribute-set";
9
+ import { AdminUpdateAttributeSet } from "../../../../../../api/admin/plugin/attribute-set/validators";
10
+ import { z } from "zod";
11
+ import { Button, Drawer, Input, Label, Textarea, toast } from "@medusajs/ui";
12
+ import { useNavigate, useParams } from "react-router-dom";
13
+ import { useEffect } from "react";
14
+
15
+ type Props = {
16
+ attributeSet: AttributeSet;
17
+ };
18
+
19
+ const FormSchema = AdminUpdateAttributeSet;
20
+ type FormValues = z.infer<typeof FormSchema>;
21
+
22
+ const AttributeSetEditPage = () => {
23
+ const { id } = useParams();
24
+ const navigate = useNavigate();
25
+
26
+ const { attributeSet, isLoading } = useAttributeSet(
27
+ id!,
28
+ {
29
+ fields: "name, handle, description",
30
+ },
31
+ { enabled: !!id }
32
+ );
33
+
34
+ const form = useForm<FormValues>({
35
+ resolver: zodResolver(FormSchema),
36
+ defaultValues: {
37
+ name: attributeSet?.name ?? "",
38
+ description: attributeSet?.description ?? "",
39
+ handle: attributeSet?.handle ?? "",
40
+ },
41
+ });
42
+
43
+ useEffect(() => {
44
+ if (attributeSet) {
45
+ form.reset({
46
+ name: attributeSet?.name ?? "",
47
+ description: attributeSet?.description ?? "",
48
+ handle: attributeSet?.handle ?? "",
49
+ })
50
+ }
51
+ }, [attributeSet, form])
52
+
53
+ const { mutateAsync, isPending } = useUpdateAttributeSet(attributeSet?.id ?? "");
54
+
55
+ const handleSubmit = form.handleSubmit(async (data) => {
56
+ await mutateAsync(data, {
57
+ onSuccess: () => {
58
+ toast.success("Attribute set edited");
59
+ navigate(-1);
60
+ },
61
+ onError: (error) => {
62
+ toast.error(error.message);
63
+ },
64
+ });
65
+ });
66
+
67
+ const handleClose = () => {
68
+ navigate(-1);
69
+ };
70
+
71
+ if (!attributeSet) {
72
+ return <p>Not found...</p>;
73
+ }
74
+
75
+ return (
76
+ <Drawer
77
+ open={true}
78
+ onOpenChange={(open) => {
79
+ if (!open) {
80
+ handleClose();
81
+ }
82
+ }}
83
+ >
84
+ <Drawer.Content>
85
+ <Drawer.Header>Edit Attribute Set</Drawer.Header>
86
+ <Drawer.Body>
87
+ <form id='attribute-set-edit-form' onSubmit={handleSubmit}>
88
+ <div className="flex flex-col gap-4">
89
+ <div className="grid grid-cols-1 gap-4 md:grid-cols-2">
90
+ <div className="flex flex-col gap-2">
91
+ <Label htmlFor="name">Name</Label>
92
+ <Input aria-invalid={!!form.formState.errors.name} size="small" {...form.register("name")} />
93
+ </div>
94
+ <div className="flex flex-col gap-2">
95
+ <Label htmlFor="handle">Handle</Label>
96
+ <Input size="small" {...form.register("handle")} />
97
+ </div>
98
+ </div>
99
+ <div className="flex flex-col gap-2">
100
+ <Label htmlFor="description">Description</Label>
101
+ <Textarea {...form.register("description")} />
102
+ </div>
103
+ </div>
104
+ </form>
105
+ </Drawer.Body>
106
+ <Drawer.Footer>
107
+ <Drawer.Close onClick={handleClose} asChild>
108
+ <Button disabled={isPending} variant="secondary">Cancel</Button>
109
+ </Drawer.Close>
110
+ <Button disabled={isPending} type="submit" form="attribute-set-edit-form" >Save</Button>
111
+ </Drawer.Footer>
112
+ </Drawer.Content>
113
+ </Drawer>
114
+ );
115
+ };
116
+
117
+ export const config = defineRouteConfig({});
118
+
119
+ export default AttributeSetEditPage;
@@ -0,0 +1,45 @@
1
+ import { useAttributeSet } from "../../../../hooks/api/attribute-set";
2
+ import { useParams } from "react-router-dom";
3
+ import {
4
+ Container,
5
+ DropdownMenu,
6
+ Heading,
7
+ IconButton,
8
+ Text,
9
+ } from "@medusajs/ui";
10
+ import { SingleColumnLayout } from "../../../../layouts/single-column";
11
+ import { EllipsisHorizontal, PencilSquare, Trash } from "@medusajs/icons";
12
+ import { SectionRow } from "../../../../components/section-row";
13
+ import { AttributeSetGeneralSection, AttributeSetAttributesSection } from "./components";
14
+
15
+ export default function AttributeSetDetail() {
16
+ const { id } = useParams();
17
+ const { attributeSet, isLoading } = useAttributeSet(id || "");
18
+
19
+ if (!id) {
20
+ return <div>Invalid attribute set ID</div>;
21
+ }
22
+
23
+ if (isLoading) {
24
+ return <div>Loading...</div>;
25
+ }
26
+
27
+ if (!attributeSet) {
28
+ return <div>Attribute set not found</div>;
29
+ }
30
+
31
+ return (
32
+ <SingleColumnLayout>
33
+ <AttributeSetGeneralSection attributeSet={attributeSet} />
34
+
35
+ <AttributeSetAttributesSection attributeSet={attributeSet} />
36
+
37
+ {/* Metadata Section */}
38
+ <Container>
39
+ <div className="flex flex-col gap-y-4 p-4">
40
+ <Heading level="h2">Metadata</Heading>
41
+ </div>
42
+ </Container>
43
+ </SingleColumnLayout>
44
+ );
45
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "useDefineForClassFields": true,
5
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
6
+ "module": "ESNext",
7
+ "skipLibCheck": true,
8
+
9
+ /* Bundler mode */
10
+ "moduleResolution": "bundler",
11
+ "allowImportingTsExtensions": true,
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "noEmit": true,
15
+ "jsx": "react-jsx",
16
+
17
+ /* Linting */
18
+ "strict": true,
19
+ "noUnusedLocals": true,
20
+ "noUnusedParameters": true,
21
+ "noFallthroughCasesInSwitch": true,
22
+
23
+ /* Type Declarations */
24
+ "typeRoots": ["./types", "./node_modules/@types"]
25
+ },
26
+ "include": [".", "types/**/*.d.ts"]
27
+ }
@@ -0,0 +1,3 @@
1
+ declare const __BACKEND_URL__: string
2
+ declare const __BASE__: string
3
+ declare const __STOREFRONT_URL__: string
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />
@@ -0,0 +1,133 @@
1
+ # Custom API Routes
2
+
3
+ An API Route is a REST API endpoint.
4
+
5
+ An API Route is created in a TypeScript or JavaScript file under the `/src/api` directory of your Medusa application. The file’s name must be `route.ts` or `route.js`.
6
+
7
+ For example, to create a `GET` API Route at `/store/hello-world`, create the file `src/api/store/hello-world/route.ts` with the following content:
8
+
9
+ ```ts
10
+ import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http";
11
+
12
+ export async function GET(req: MedusaRequest, res: MedusaResponse) {
13
+ res.json({
14
+ message: "Hello world!",
15
+ });
16
+ }
17
+ ```
18
+
19
+ ## Supported HTTP methods
20
+
21
+ The file based routing supports the following HTTP methods:
22
+
23
+ - GET
24
+ - POST
25
+ - PUT
26
+ - PATCH
27
+ - DELETE
28
+ - OPTIONS
29
+ - HEAD
30
+
31
+ You can define a handler for each of these methods by exporting a function with the name of the method in the paths `route.ts` file.
32
+
33
+ For example:
34
+
35
+ ```ts
36
+ import type { MedusaRequest, MedusaResponse } from "@medusajs/framework/http";
37
+
38
+ export async function GET(req: MedusaRequest, res: MedusaResponse) {
39
+ // Handle GET requests
40
+ }
41
+
42
+ export async function POST(req: MedusaRequest, res: MedusaResponse) {
43
+ // Handle POST requests
44
+ }
45
+
46
+ export async function PUT(req: MedusaRequest, res: MedusaResponse) {
47
+ // Handle PUT requests
48
+ }
49
+ ```
50
+
51
+ ## Parameters
52
+
53
+ To create an API route that accepts a path parameter, create a directory within the route's path whose name is of the format `[param]`.
54
+
55
+ For example, if you want to define a route that takes a `productId` parameter, you can do so by creating a file called `/api/products/[productId]/route.ts`:
56
+
57
+ ```ts
58
+ import type {
59
+ MedusaRequest,
60
+ MedusaResponse,
61
+ } from "@medusajs/framework/http"
62
+
63
+ export async function GET(req: MedusaRequest, res: MedusaResponse) {
64
+ const { productId } = req.params;
65
+
66
+ res.json({
67
+ message: `You're looking for product ${productId}`
68
+ })
69
+ }
70
+ ```
71
+
72
+ To create an API route that accepts multiple path parameters, create within the file's path multiple directories whose names are of the format `[param]`.
73
+
74
+ For example, if you want to define a route that takes both a `productId` and a `variantId` parameter, you can do so by creating a file called `/api/products/[productId]/variants/[variantId]/route.ts`.
75
+
76
+ ## Using the container
77
+
78
+ The Medusa container is available on `req.scope`. Use it to access modules' main services and other registered resources:
79
+
80
+ ```ts
81
+ import type {
82
+ MedusaRequest,
83
+ MedusaResponse,
84
+ } from "@medusajs/framework/http"
85
+
86
+ export const GET = async (
87
+ req: MedusaRequest,
88
+ res: MedusaResponse
89
+ ) => {
90
+ const productModuleService = req.scope.resolve("product")
91
+
92
+ const [, count] = await productModuleService.listAndCount()
93
+
94
+ res.json({
95
+ count,
96
+ })
97
+ }
98
+ ```
99
+
100
+ ## Middleware
101
+
102
+ You can apply middleware to your routes by creating a file called `/api/middlewares.ts`. This file must export a configuration object with what middleware you want to apply to which routes.
103
+
104
+ For example, if you want to apply a custom middleware function to the `/store/custom` route, you can do so by adding the following to your `/api/middlewares.ts` file:
105
+
106
+ ```ts
107
+ import { defineMiddlewares } from "@medusajs/framework/http"
108
+ import type {
109
+ MedusaRequest,
110
+ MedusaResponse,
111
+ MedusaNextFunction,
112
+ } from "@medusajs/framework/http";
113
+
114
+ async function logger(
115
+ req: MedusaRequest,
116
+ res: MedusaResponse,
117
+ next: MedusaNextFunction
118
+ ) {
119
+ console.log("Request received");
120
+ next();
121
+ }
122
+
123
+ export default defineMiddlewares({
124
+ routes: [
125
+ {
126
+ matcher: "/store/custom",
127
+ middlewares: [logger],
128
+ },
129
+ ],
130
+ })
131
+ ```
132
+
133
+ The `matcher` property can be either a string or a regular expression. The `middlewares` property accepts an array of middleware functions.
@@ -0,0 +1,8 @@
1
+ import { MiddlewareRoute } from "@medusajs/framework";
2
+ import { adminAttributeRoutesMiddlewares } from "./plugin/attributes/middlewares";
3
+ import { adminAttributeSetMiddlewares } from "./plugin/attribute-set/middlewares";
4
+
5
+ export const adminRoutesMiddlewares: MiddlewareRoute[] = [
6
+ ...adminAttributeRoutesMiddlewares,
7
+ ...adminAttributeSetMiddlewares,
8
+ ]
@@ -0,0 +1,17 @@
1
+ import { MedusaRequest, MedusaResponse } from "@medusajs/framework";
2
+ import { AdminBatchLinkAttributeSetAttributesType } from "../../validators";
3
+ import { batchLinkAttributeSetAttributesWorkflow } from "../../../../../../workflows/attribute-set/workflows";
4
+
5
+ export const POST = async (req: MedusaRequest<AdminBatchLinkAttributeSetAttributesType>, res: MedusaResponse) => {
6
+ const attributeSetId = req.params.id
7
+ const payload = req.validatedBody
8
+
9
+ await batchLinkAttributeSetAttributesWorkflow(req.scope).run({
10
+ input: {
11
+ ...payload,
12
+ id: attributeSetId
13
+ }
14
+ })
15
+
16
+ return res.status(200).json({})
17
+ }
@@ -0,0 +1,41 @@
1
+ import { MedusaRequest, MedusaResponse, refetchEntity } from "@medusajs/framework";
2
+ import { AdminGetAttributeParamsType } from "../../attributes/validators";
3
+ import { ContainerRegistrationKeys } from "@medusajs/framework/utils";
4
+ import { updateAttributeSetWorkflow } from "../../../../../workflows/attribute-set/workflows";
5
+ import { AdminUpdateAttributeSetType } from "../validators";
6
+
7
+ export const GET = async (req: MedusaRequest<AdminGetAttributeParamsType>, res: MedusaResponse) => {
8
+ const id = req.params.id
9
+ const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
10
+
11
+ const { data: [attributeSet] } = await query.graph({
12
+ entity: 'attribute_set',
13
+ filters: { id },
14
+ ...req.queryConfig,
15
+ }, {
16
+ throwIfKeyNotFound: true,
17
+ })
18
+
19
+ return res.status(200).json({ attributeSet })
20
+ }
21
+
22
+ export const POST = async (req: MedusaRequest<AdminUpdateAttributeSetType>, res: MedusaResponse) => {
23
+ const id = req.params.id
24
+ const body = req.validatedBody
25
+
26
+ await updateAttributeSetWorkflow(req.scope).run({
27
+ input: {
28
+ ...body,
29
+ id,
30
+ }
31
+ })
32
+
33
+ const attributeSet = await refetchEntity(
34
+ 'attribute_set',
35
+ id,
36
+ req.scope,
37
+ req.queryConfig.fields,
38
+ )
39
+
40
+ return res.status(200).json({ attributeSet })
41
+ }
@@ -0,0 +1,42 @@
1
+ import { AdminBatchLinkAttributeSetAttributes, AdminCreateAttributeSet, AdminGetAttributeSetParams, AdminGetAttributeSetsParams, AdminUpdateAttributeSet } from "./validators";
2
+ import { MiddlewareRoute, validateAndTransformBody, validateAndTransformQuery } from "@medusajs/framework";
3
+
4
+ import { listAttributeSetQueryConfig, retrieveAttributeSetQueryConfig } from "./query-config";
5
+
6
+ export const adminAttributeSetMiddlewares: MiddlewareRoute[] = [
7
+ {
8
+ matcher: '/admin/plugin/attribute-set',
9
+ method: ['GET'],
10
+ middlewares: [validateAndTransformQuery(AdminGetAttributeSetsParams, listAttributeSetQueryConfig)]
11
+ },
12
+ {
13
+ matcher: '/admin/plugin/attribute-set',
14
+ methods: ['POST'],
15
+ middlewares: [
16
+ validateAndTransformQuery(AdminGetAttributeSetParams, retrieveAttributeSetQueryConfig),
17
+ validateAndTransformBody(AdminCreateAttributeSet)
18
+ ]
19
+ },
20
+ {
21
+ matcher: '/admin/plugin/attribute-set/:id',
22
+ method: ['GET'],
23
+ middlewares: [
24
+ validateAndTransformQuery(AdminGetAttributeSetParams, retrieveAttributeSetQueryConfig)
25
+ ]
26
+ },
27
+ {
28
+ matcher: '/admin/plugin/attribute-set/:id',
29
+ method: ['POST'],
30
+ middlewares: [
31
+ validateAndTransformQuery(AdminGetAttributeSetParams, retrieveAttributeSetQueryConfig),
32
+ validateAndTransformBody(AdminUpdateAttributeSet)
33
+ ]
34
+ },
35
+ {
36
+ matcher: '/admin/plugin/attribute-set/:id/attributes',
37
+ method: ['POST'],
38
+ middlewares: [
39
+ validateAndTransformBody(AdminBatchLinkAttributeSetAttributes)
40
+ ]
41
+ }
42
+ ]
@@ -0,0 +1,20 @@
1
+ export const defaultAdminAttributeSetFields = [
2
+ 'id',
3
+ 'name',
4
+ 'description',
5
+ 'handle',
6
+ 'metadata',
7
+ '*attributes',
8
+ '*attributes.possible_values',
9
+ ]
10
+
11
+ export const retrieveAttributeSetQueryConfig = {
12
+ defaults: defaultAdminAttributeSetFields,
13
+ isList: false,
14
+ }
15
+
16
+ export const listAttributeSetQueryConfig = {
17
+ ...retrieveAttributeSetQueryConfig,
18
+ defaultLimit: 50,
19
+ isList: true,
20
+ }
@@ -0,0 +1,34 @@
1
+ import { MedusaRequest, MedusaResponse, refetchEntity } from "@medusajs/framework";
2
+
3
+ import { AdminCreateAttributeSetType, AdminGetAttributesSetsParamsType } from "./validators";
4
+ import { createAttributeSetWorkflow } from "../../../../workflows/attribute-set/workflows/create-attribute-set";
5
+ import { ContainerRegistrationKeys } from "@medusajs/framework/utils";
6
+ import { AttributeSet } from "../../../../types/attribute";
7
+ import { PaginatedResponse } from "@medusajs/framework/types";
8
+
9
+ export const POST = async (req: MedusaRequest<AdminCreateAttributeSetType>, res: MedusaResponse) => {
10
+ const { result: [attributeSet] } = await createAttributeSetWorkflow(req.scope).run({
11
+ input: [req.validatedBody]
12
+ })
13
+
14
+ const response = await refetchEntity(
15
+ 'attribute_set',
16
+ attributeSet.id,
17
+ req.scope,
18
+ req.queryConfig.fields,
19
+ )
20
+
21
+ return res.status(201).json({ attribute_set: response })
22
+ }
23
+
24
+ export const GET = async (req:MedusaRequest<AdminGetAttributesSetsParamsType>, res: MedusaResponse) => {
25
+ const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
26
+
27
+ const { data: attributeSets, metadata } = await query.graph({
28
+ entity: 'attribute_set',
29
+ filters: req.filterableFields,
30
+ ...req.queryConfig
31
+ })
32
+
33
+ return res.status(200).json({ attributeSets, count: metadata?.count, offset: metadata?.skip, limit: metadata?.take })
34
+ }
@@ -0,0 +1,45 @@
1
+ import { applyAndAndOrOperators } from '@medusajs/medusa/api/utils/common-validators/common'
2
+ import { createFindParams, createOperatorMap, createSelectParams } from '@medusajs/medusa/api/utils/validators'
3
+ import { z } from 'zod'
4
+
5
+ export const AdminGetAttributeSetParams = createSelectParams()
6
+ export type AdminGetAttributeSetParamsType = z.infer<typeof AdminGetAttributeSetParams>
7
+
8
+ export const GetAttributeSetsParams = z.object({
9
+ id: z.string().optional(),
10
+ name: z.string().optional(),
11
+ handle: z.string().optional(),
12
+ created_at: createOperatorMap().optional(),
13
+ updated_at: createOperatorMap().optional(),
14
+ deleted_at: createOperatorMap().optional(),
15
+ })
16
+ export const AdminGetAttributeSetsParams = createFindParams({
17
+ offset: 0,
18
+ limit: 50,
19
+ })
20
+ .merge(applyAndAndOrOperators(GetAttributeSetsParams))
21
+ .merge(GetAttributeSetsParams)
22
+
23
+ export type AdminGetAttributesSetsParamsType = z.infer<typeof AdminGetAttributeSetsParams>
24
+
25
+ const AdminBaseAttributeSet = z.object({
26
+ name: z.string().optional(),
27
+ description: z.string().optional(),
28
+ handle: z.string().optional(),
29
+ metadata: z.record(z.unknown()).nullish(),
30
+ attributes: z.array(z.string()).optional(),
31
+ }).strict()
32
+
33
+ export type AdminCreateAttributeSetType = z.infer<typeof AdminCreateAttributeSet>
34
+ export const AdminCreateAttributeSet = AdminBaseAttributeSet.merge(z.object({
35
+ name: z.string().min(1),
36
+ })).strict()
37
+
38
+ export type AdminUpdateAttributeSetType = z.infer<typeof AdminUpdateAttributeSet>
39
+ export const AdminUpdateAttributeSet = AdminBaseAttributeSet.merge(z.object({ name: z.string().min(1) }))
40
+
41
+ export type AdminBatchLinkAttributeSetAttributesType = z.infer<typeof AdminBatchLinkAttributeSetAttributes>
42
+ export const AdminBatchLinkAttributeSetAttributes = z.object({
43
+ add: z.array(z.string()).optional(),
44
+ remove: z.array(z.string()).optional(),
45
+ })
@@ -0,0 +1,85 @@
1
+ import { MedusaRequest, MedusaResponse, refetchEntities } from "@medusajs/framework";
2
+ import { AdminGetAttributeParamsType, AdminUpdateAttributeType } from "../validators";
3
+ import { ContainerRegistrationKeys, MedusaError, MedusaErrorTypes } from "@medusajs/framework/utils";
4
+ import { updateAttributesWorkflow } from "../../../../../workflows";
5
+ import { UpdateAttributeDTO } from "../../../../../modules/attribute/types/attribute/common";
6
+ import { deleteAttributeWorkflow } from "../../../../../workflows/attribute/workflows/delete-attribute";
7
+
8
+ export const POST = async (req: MedusaRequest<UpdateAttributeDTO>, res: MedusaResponse) => {
9
+ const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
10
+
11
+ const attributeId = req.params.id
12
+
13
+ const { data: [existingAttribute] } = await query.graph({
14
+ entity: 'attribute',
15
+ fields: ['id'],
16
+ filters: {
17
+ id: attributeId
18
+ }
19
+ })
20
+
21
+ if (!existingAttribute) {
22
+ throw new MedusaError(MedusaErrorTypes.NOT_FOUND, `Attribute with id '${attributeId}' not found`)
23
+ }
24
+
25
+ await updateAttributesWorkflow(req.scope).run({
26
+ input: { attributes: [{
27
+ ...req.validatedBody,
28
+ id: attributeId
29
+ }] }
30
+ })
31
+
32
+ const attribute = await refetchEntities(
33
+ 'attribute',
34
+ attributeId,
35
+ req.scope,
36
+ req.queryConfig.fields
37
+ )
38
+
39
+ return res.status(201).json({ attribute })
40
+ }
41
+
42
+ export const GET = async (req: MedusaRequest<AdminGetAttributeParamsType>, res: MedusaResponse) => {
43
+ const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
44
+
45
+ const attributeId = req.params.id
46
+
47
+ const { data: [attribute] } = await query.graph({
48
+ entity: 'attribute',
49
+ ...req.queryConfig,
50
+ filters: {
51
+ id: attributeId,
52
+ },
53
+ })
54
+
55
+ if (!attribute) {
56
+ throw new MedusaError(MedusaErrorTypes.NOT_FOUND, 'Attribute not found')
57
+ }
58
+
59
+ return res.status(200).json({ attribute })
60
+ }
61
+
62
+ export const DELETE = async (req: MedusaRequest, res: MedusaResponse) => {
63
+ const attributeId = req.params.id
64
+ const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
65
+
66
+ const { data: [attribute] } = await query.graph({
67
+ entity: 'attribute',
68
+ fields: ['id'],
69
+ filters: {
70
+ id: attributeId,
71
+ },
72
+ })
73
+
74
+ if (!attribute) {
75
+ throw new MedusaError(MedusaErrorTypes.NOT_FOUND, 'Attribute not found')
76
+ }
77
+
78
+ await deleteAttributeWorkflow(req.scope).run({
79
+ input: {
80
+ id: attributeId
81
+ }
82
+ })
83
+
84
+ return res.status(200).json({})
85
+ }
@@ -0,0 +1,41 @@
1
+ import { ContainerRegistrationKeys, MedusaError, MedusaErrorTypes } from "@medusajs/framework/utils";
2
+ import { MedusaRequest, MedusaResponse, refetchEntity } from "@medusajs/framework";
3
+
4
+ import { AdminGetAttributeValueParamsType, AdminUpdateAttributeValueType } from "../../../validators";
5
+ import { updateAttributePossibleValueWorkflow } from "../../../../../../../workflows/attribute_possible_value";
6
+
7
+ export const GET = async (req: MedusaRequest<AdminGetAttributeValueParamsType>, res: MedusaResponse) => {
8
+ const attributeId = req.params.valueId
9
+ const query = req.scope.resolve(ContainerRegistrationKeys.QUERY)
10
+
11
+ const { data: [attributePossibleValue] } = await query.graph({
12
+ entity: 'attribute_possible_value',
13
+ ...req.queryConfig,
14
+ filters: {
15
+ ...req.filterableFields,
16
+ id: attributeId
17
+ }
18
+ })
19
+
20
+ if (!attributePossibleValue) {
21
+ throw new MedusaError(MedusaErrorTypes.NOT_FOUND, `Attribute possible value with id '${attributeId}' was not found`)
22
+ }
23
+
24
+ return res.status(200).json({ attributePossibleValue })
25
+ }
26
+
27
+ export const POST = async (req: MedusaRequest<AdminUpdateAttributeValueType>, res: MedusaResponse) => {
28
+ const { valueId } = req.params
29
+ const body = req.validatedBody
30
+
31
+ await updateAttributePossibleValueWorkflow(req.scope).run({
32
+ input: {
33
+ ...body,
34
+ id: valueId
35
+ }
36
+ })
37
+
38
+ const attributePossibleValue = await refetchEntity('attribute_possible_value', valueId, req.scope, req.queryConfig.fields)
39
+
40
+ return res.status(200).json({ attributePossibleValue: attributePossibleValue })
41
+ }