medusa-dynamic-metadata 0.0.1

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.
@@ -0,0 +1,1730 @@
1
+ import { jsxs, jsx, Fragment } from "react/jsx-runtime";
2
+ import { defineWidgetConfig } from "@medusajs/admin-sdk";
3
+ import { useState, useRef, useEffect, useMemo } from "react";
4
+ import { Container, Heading, Badge, Text, Skeleton, InlineTip, Button, Switch, Textarea, Input, toast } from "@medusajs/ui";
5
+ import { useQuery, useQueryClient } from "@tanstack/react-query";
6
+ const METADATA_FIELD_TYPES = ["number", "text", "file", "bool"];
7
+ const VALID_FIELD_TYPES = new Set(METADATA_FIELD_TYPES);
8
+ const BOOLEAN_TRUES = /* @__PURE__ */ new Set(["true", "1", "yes", "y", "on"]);
9
+ const BOOLEAN_FALSES = /* @__PURE__ */ new Set(["false", "0", "no", "n", "off"]);
10
+ function normalizeMetadataDescriptors(input) {
11
+ if (!Array.isArray(input)) return [];
12
+ const seenKeys = /* @__PURE__ */ new Set();
13
+ return input.filter(
14
+ (item) => item && typeof item === "object"
15
+ ).map((item) => {
16
+ const key = normalizeKey(item.key);
17
+ const type = normalizeType(item.type);
18
+ const label = normalizeLabel(item.label);
19
+ const filterable = !!item.filterable;
20
+ return { key, type, label, filterable };
21
+ }).filter(({ key, type }) => key && type && !seenKeys.has(key)).map(({ key, type, label, filterable }) => {
22
+ seenKeys.add(key);
23
+ return {
24
+ key,
25
+ type,
26
+ ...label && { label },
27
+ ...filterable && { filterable: true }
28
+ };
29
+ });
30
+ }
31
+ function buildInitialFormState(descriptors, metadata) {
32
+ const base = metadata && typeof metadata === "object" ? metadata : {};
33
+ return descriptors.reduce((acc, descriptor) => {
34
+ acc[descriptor.key] = normalizeFormValue(descriptor, base[descriptor.key]);
35
+ return acc;
36
+ }, {});
37
+ }
38
+ function buildMetadataPayload({
39
+ descriptors,
40
+ values,
41
+ originalMetadata
42
+ }) {
43
+ const base = originalMetadata && typeof originalMetadata === "object" ? { ...originalMetadata } : {};
44
+ descriptors.forEach((descriptor) => {
45
+ const coerced = coerceMetadataValue(descriptor, values[descriptor.key]);
46
+ if (coerced === void 0) {
47
+ delete base[descriptor.key];
48
+ } else {
49
+ base[descriptor.key] = coerced;
50
+ }
51
+ });
52
+ return base;
53
+ }
54
+ function hasMetadataChanges({
55
+ descriptors,
56
+ values,
57
+ originalMetadata
58
+ }) {
59
+ const next = buildMetadataPayload({ descriptors, values, originalMetadata });
60
+ const prev = originalMetadata && typeof originalMetadata === "object" ? originalMetadata : {};
61
+ return descriptors.some(({ key }) => !isDeepEqual(prev[key], next[key]));
62
+ }
63
+ function validateValueForDescriptor(descriptor, value) {
64
+ if (descriptor.type === "number") {
65
+ if (value == null || value === "") return void 0;
66
+ const num = typeof value === "number" ? value : Number(String(value).trim());
67
+ return isNaN(num) ? "Enter a valid number" : void 0;
68
+ }
69
+ if (descriptor.type === "file") {
70
+ if (!value) return void 0;
71
+ try {
72
+ new URL(String(value).trim());
73
+ return void 0;
74
+ } catch {
75
+ return "Enter a valid URL";
76
+ }
77
+ }
78
+ return void 0;
79
+ }
80
+ function normalizeFormValue(descriptor, currentValue) {
81
+ if (descriptor.type === "bool") return Boolean(currentValue);
82
+ if ((descriptor.type === "number" || descriptor.type === "text") && typeof currentValue === "number") {
83
+ return currentValue.toString();
84
+ }
85
+ if (typeof currentValue === "string" || typeof currentValue === "number") {
86
+ return String(currentValue);
87
+ }
88
+ return "";
89
+ }
90
+ function coerceMetadataValue(descriptor, value) {
91
+ if (value == null || value === "") return void 0;
92
+ if (descriptor.type === "bool") {
93
+ if (typeof value === "boolean") return value;
94
+ if (typeof value === "number") return value !== 0;
95
+ const normalized = String(value).trim().toLowerCase();
96
+ if (!normalized) return void 0;
97
+ if (BOOLEAN_TRUES.has(normalized)) return true;
98
+ if (BOOLEAN_FALSES.has(normalized)) return false;
99
+ return Boolean(value);
100
+ }
101
+ if (descriptor.type === "number") {
102
+ const num = typeof value === "number" ? value : Number(String(value).trim());
103
+ return isNaN(num) ? void 0 : num;
104
+ }
105
+ const trimmed = String(value).trim();
106
+ if (!trimmed) return void 0;
107
+ return trimmed;
108
+ }
109
+ function normalizeKey(value) {
110
+ return typeof value === "string" ? value.trim() || void 0 : void 0;
111
+ }
112
+ function normalizeType(value) {
113
+ if (typeof value !== "string") return void 0;
114
+ const type = value.trim().toLowerCase();
115
+ return VALID_FIELD_TYPES.has(type) ? type : void 0;
116
+ }
117
+ function normalizeLabel(value) {
118
+ return typeof value === "string" ? value.trim() || void 0 : void 0;
119
+ }
120
+ function isDeepEqual(a, b) {
121
+ if (a === b) return true;
122
+ if (!a || !b || typeof a !== "object" || typeof b !== "object") return false;
123
+ const aKeys = Object.keys(a);
124
+ const bKeys = Object.keys(b);
125
+ if (aKeys.length !== bKeys.length) return false;
126
+ return aKeys.every(
127
+ (key) => isDeepEqual(a[key], b[key])
128
+ );
129
+ }
130
+ const CONFIG_ENDPOINT = "/admin/metadata-config";
131
+ const QUERY_KEY = ["medusa-dynamic-metadata", "metadata-config"];
132
+ function useMetadataConfig({ entity }) {
133
+ return useQuery({
134
+ queryKey: [...QUERY_KEY, entity],
135
+ queryFn: async () => {
136
+ const response = await fetch(`${CONFIG_ENDPOINT}?entity=${entity}`, {
137
+ credentials: "include"
138
+ });
139
+ if (!response.ok) {
140
+ throw new Error("Unable to load metadata configuration");
141
+ }
142
+ const payload = await response.json();
143
+ return normalizeMetadataDescriptors(payload.metadataDescriptors);
144
+ },
145
+ staleTime: 5 * 60 * 1e3
146
+ });
147
+ }
148
+ const DEFAULT_ENTITY_MAPPINGS = {
149
+ products: {
150
+ widgetZone: "product.details.after",
151
+ apiEndpoint: "/admin/products/{id}",
152
+ responseKey: "product"
153
+ },
154
+ orders: {
155
+ widgetZone: "order.details.after",
156
+ apiEndpoint: "/admin/orders/{id}",
157
+ responseKey: "order"
158
+ },
159
+ categories: {
160
+ widgetZone: "product_category.details.after",
161
+ apiEndpoint: "/admin/product-categories/{id}",
162
+ responseKey: "product_category"
163
+ },
164
+ collections: {
165
+ widgetZone: "product_collection.details.after",
166
+ apiEndpoint: "/admin/collections/{id}",
167
+ responseKey: "collection"
168
+ },
169
+ customers: {
170
+ widgetZone: "customer.details.after",
171
+ apiEndpoint: "/admin/customers/{id}",
172
+ responseKey: "customer"
173
+ },
174
+ regions: {
175
+ widgetZone: "region.details.after",
176
+ apiEndpoint: "/admin/regions/{id}",
177
+ responseKey: "region"
178
+ },
179
+ sales_channels: {
180
+ widgetZone: "sales_channel.details.after",
181
+ apiEndpoint: "/admin/sales-channels/{id}",
182
+ responseKey: "sales_channel"
183
+ },
184
+ stores: {
185
+ widgetZone: "store.details.after",
186
+ apiEndpoint: "/admin/stores/{id}",
187
+ responseKey: "store"
188
+ },
189
+ promotions: {
190
+ widgetZone: "promotion.details.after",
191
+ apiEndpoint: "/admin/promotions/{id}",
192
+ responseKey: "promotion"
193
+ },
194
+ campaigns: {
195
+ widgetZone: "campaign.details.after",
196
+ apiEndpoint: "/admin/campaigns/{id}",
197
+ responseKey: "campaign"
198
+ },
199
+ price_lists: {
200
+ widgetZone: "price_list.details.after",
201
+ apiEndpoint: "/admin/price-lists/{id}",
202
+ responseKey: "price_list"
203
+ },
204
+ shipping_profiles: {
205
+ widgetZone: "shipping_profile.details.after",
206
+ apiEndpoint: "/admin/shipping-profiles/{id}",
207
+ responseKey: "shipping_profile"
208
+ },
209
+ return_reasons: {
210
+ widgetZone: "return_reason.details.after",
211
+ apiEndpoint: "/admin/return-reasons/{id}",
212
+ responseKey: "return_reason"
213
+ },
214
+ inventory_items: {
215
+ widgetZone: "inventory_item.details.after",
216
+ apiEndpoint: "/admin/inventory-items/{id}",
217
+ responseKey: "inventory_item"
218
+ },
219
+ product_variants: {
220
+ widgetZone: "product_variant.details.after",
221
+ apiEndpoint: "/admin/product-variants/{id}",
222
+ responseKey: "product_variant"
223
+ },
224
+ account_holders: {
225
+ widgetZone: "account_holder.details.after",
226
+ apiEndpoint: "/admin/account-holders/{id}",
227
+ responseKey: "account_holder"
228
+ },
229
+ captures: {
230
+ widgetZone: "capture.details.after",
231
+ apiEndpoint: "/admin/captures/{id}",
232
+ responseKey: "capture"
233
+ },
234
+ carts: {
235
+ widgetZone: "cart.details.after",
236
+ apiEndpoint: "/admin/carts/{id}",
237
+ responseKey: "cart"
238
+ },
239
+ cart_addresses: {
240
+ widgetZone: "cart_address.details.after",
241
+ apiEndpoint: "/admin/cart-addresses/{id}",
242
+ responseKey: "cart_address"
243
+ },
244
+ cart_line_items: {
245
+ widgetZone: "cart_line_item.details.after",
246
+ apiEndpoint: "/admin/cart-line-items/{id}",
247
+ responseKey: "cart_line_item"
248
+ },
249
+ cart_line_item_adjustments: {
250
+ widgetZone: "cart_line_item_adjustment.details.after",
251
+ apiEndpoint: "/admin/cart-line-item-adjustments/{id}",
252
+ responseKey: "cart_line_item_adjustment"
253
+ },
254
+ cart_line_item_tax_lines: {
255
+ widgetZone: "cart_line_item_tax_line.details.after",
256
+ apiEndpoint: "/admin/cart-line-item-tax-lines/{id}",
257
+ responseKey: "cart_line_item_tax_line"
258
+ },
259
+ cart_shipping_methods: {
260
+ widgetZone: "cart_shipping_method.details.after",
261
+ apiEndpoint: "/admin/cart-shipping-methods/{id}",
262
+ responseKey: "cart_shipping_method"
263
+ },
264
+ cart_shipping_method_adjustments: {
265
+ widgetZone: "cart_shipping_method_adjustment.details.after",
266
+ apiEndpoint: "/admin/cart-shipping-method-adjustments/{id}",
267
+ responseKey: "cart_shipping_method_adjustment"
268
+ },
269
+ cart_shipping_method_tax_lines: {
270
+ widgetZone: "cart_shipping_method_tax_line.details.after",
271
+ apiEndpoint: "/admin/cart-shipping-method-tax-lines/{id}",
272
+ responseKey: "cart_shipping_method_tax_line"
273
+ },
274
+ contact_email_subscriptions: {
275
+ widgetZone: "contact_email_subscription.details.after",
276
+ apiEndpoint: "/admin/contact-email-subscriptions/{id}",
277
+ responseKey: "contact_email_subscription"
278
+ },
279
+ contact_requests: {
280
+ widgetZone: "contact_request.details.after",
281
+ apiEndpoint: "/admin/contact-requests/{id}",
282
+ responseKey: "contact_request"
283
+ },
284
+ credit_lines: {
285
+ widgetZone: "credit_line.details.after",
286
+ apiEndpoint: "/admin/credit-lines/{id}",
287
+ responseKey: "credit_line"
288
+ },
289
+ customer_addresses: {
290
+ widgetZone: "customer_address.details.after",
291
+ apiEndpoint: "/admin/customer-addresses/{id}",
292
+ responseKey: "customer_address"
293
+ },
294
+ customer_groups: {
295
+ widgetZone: "customer_group.details.after",
296
+ apiEndpoint: "/admin/customer-groups/{id}",
297
+ responseKey: "customer_group"
298
+ },
299
+ customer_group_customers: {
300
+ widgetZone: "customer_group_customer.details.after",
301
+ apiEndpoint: "/admin/customer-group-customers/{id}",
302
+ responseKey: "customer_group_customer"
303
+ },
304
+ fulfillments: {
305
+ widgetZone: "fulfillment.details.after",
306
+ apiEndpoint: "/admin/fulfillments/{id}",
307
+ responseKey: "fulfillment"
308
+ },
309
+ fulfillment_addresses: {
310
+ widgetZone: "fulfillment_address.details.after",
311
+ apiEndpoint: "/admin/fulfillment-addresses/{id}",
312
+ responseKey: "fulfillment_address"
313
+ },
314
+ fulfillment_sets: {
315
+ widgetZone: "fulfillment_set.details.after",
316
+ apiEndpoint: "/admin/fulfillment-sets/{id}",
317
+ responseKey: "fulfillment_set"
318
+ },
319
+ geo_zones: {
320
+ widgetZone: "geo_zone.details.after",
321
+ apiEndpoint: "/admin/geo-zones/{id}",
322
+ responseKey: "geo_zone"
323
+ },
324
+ images: {
325
+ widgetZone: "image.details.after",
326
+ apiEndpoint: "/admin/images/{id}",
327
+ responseKey: "image"
328
+ },
329
+ inventory_levels: {
330
+ widgetZone: "inventory_level.details.after",
331
+ apiEndpoint: "/admin/inventory-levels/{id}",
332
+ responseKey: "inventory_level"
333
+ },
334
+ invites: {
335
+ widgetZone: "invite.details.after",
336
+ apiEndpoint: "/admin/invites/{id}",
337
+ responseKey: "invite"
338
+ },
339
+ order_addresses: {
340
+ widgetZone: "order_address.details.after",
341
+ apiEndpoint: "/admin/order-addresses/{id}",
342
+ responseKey: "order_address"
343
+ },
344
+ order_changes: {
345
+ widgetZone: "order_change.details.after",
346
+ apiEndpoint: "/admin/order-changes/{id}",
347
+ responseKey: "order_change"
348
+ },
349
+ order_claims: {
350
+ widgetZone: "order_claim.details.after",
351
+ apiEndpoint: "/admin/order-claims/{id}",
352
+ responseKey: "order_claim"
353
+ },
354
+ order_claim_items: {
355
+ widgetZone: "order_claim_item.details.after",
356
+ apiEndpoint: "/admin/order-claim-items/{id}",
357
+ responseKey: "order_claim_item"
358
+ },
359
+ order_claim_item_images: {
360
+ widgetZone: "order_claim_item_image.details.after",
361
+ apiEndpoint: "/admin/order-claim-item-images/{id}",
362
+ responseKey: "order_claim_item_image"
363
+ },
364
+ order_credit_lines: {
365
+ widgetZone: "order_credit_line.details.after",
366
+ apiEndpoint: "/admin/order-credit-lines/{id}",
367
+ responseKey: "order_credit_line"
368
+ },
369
+ order_exchanges: {
370
+ widgetZone: "order_exchange.details.after",
371
+ apiEndpoint: "/admin/order-exchanges/{id}",
372
+ responseKey: "order_exchange"
373
+ },
374
+ order_exchange_items: {
375
+ widgetZone: "order_exchange_item.details.after",
376
+ apiEndpoint: "/admin/order-exchange-items/{id}",
377
+ responseKey: "order_exchange_item"
378
+ },
379
+ order_items: {
380
+ widgetZone: "order_item.details.after",
381
+ apiEndpoint: "/admin/order-items/{id}",
382
+ responseKey: "order_item"
383
+ },
384
+ order_line_items: {
385
+ widgetZone: "order_line_item.details.after",
386
+ apiEndpoint: "/admin/order-line-items/{id}",
387
+ responseKey: "order_line_item"
388
+ },
389
+ order_shipping_methods: {
390
+ widgetZone: "order_shipping_method.details.after",
391
+ apiEndpoint: "/admin/order-shipping-methods/{id}",
392
+ responseKey: "order_shipping_method"
393
+ },
394
+ payments: {
395
+ widgetZone: "payment.details.after",
396
+ apiEndpoint: "/admin/payments/{id}",
397
+ responseKey: "payment"
398
+ },
399
+ payment_collections: {
400
+ widgetZone: "payment_collection.details.after",
401
+ apiEndpoint: "/admin/payment-collections/{id}",
402
+ responseKey: "payment_collection"
403
+ },
404
+ payment_sessions: {
405
+ widgetZone: "payment_session.details.after",
406
+ apiEndpoint: "/admin/payment-sessions/{id}",
407
+ responseKey: "payment_session"
408
+ },
409
+ product_options: {
410
+ widgetZone: "product_option.details.after",
411
+ apiEndpoint: "/admin/product-options/{id}",
412
+ responseKey: "product_option"
413
+ },
414
+ product_option_values: {
415
+ widgetZone: "product_option_value.details.after",
416
+ apiEndpoint: "/admin/product-option-values/{id}",
417
+ responseKey: "product_option_value"
418
+ },
419
+ product_tags: {
420
+ widgetZone: "product_tag.details.after",
421
+ apiEndpoint: "/admin/product-tags/{id}",
422
+ responseKey: "product_tag"
423
+ },
424
+ product_types: {
425
+ widgetZone: "product_type.details.after",
426
+ apiEndpoint: "/admin/product-types/{id}",
427
+ responseKey: "product_type"
428
+ },
429
+ refunds: {
430
+ widgetZone: "refund.details.after",
431
+ apiEndpoint: "/admin/refunds/{id}",
432
+ responseKey: "refund"
433
+ },
434
+ refund_reasons: {
435
+ widgetZone: "refund_reason.details.after",
436
+ apiEndpoint: "/admin/refund-reasons/{id}",
437
+ responseKey: "refund_reason"
438
+ },
439
+ region_countries: {
440
+ widgetZone: "region_country.details.after",
441
+ apiEndpoint: "/admin/region-countries/{id}",
442
+ responseKey: "region_country"
443
+ },
444
+ reservation_items: {
445
+ widgetZone: "reservation_item.details.after",
446
+ apiEndpoint: "/admin/reservation-items/{id}",
447
+ responseKey: "reservation_item"
448
+ },
449
+ returns: {
450
+ widgetZone: "return.details.after",
451
+ apiEndpoint: "/admin/returns/{id}",
452
+ responseKey: "return"
453
+ },
454
+ return_items: {
455
+ widgetZone: "return_item.details.after",
456
+ apiEndpoint: "/admin/return-items/{id}",
457
+ responseKey: "return_item"
458
+ },
459
+ service_zones: {
460
+ widgetZone: "service_zone.details.after",
461
+ apiEndpoint: "/admin/service-zones/{id}",
462
+ responseKey: "service_zone"
463
+ },
464
+ shipping_options: {
465
+ widgetZone: "shipping_option.details.after",
466
+ apiEndpoint: "/admin/shipping-options/{id}",
467
+ responseKey: "shipping_option"
468
+ },
469
+ stock_locations: {
470
+ widgetZone: "stock_location.details.after",
471
+ apiEndpoint: "/admin/stock-locations/{id}",
472
+ responseKey: "stock_location"
473
+ },
474
+ stock_location_addresses: {
475
+ widgetZone: "stock_location_address.details.after",
476
+ apiEndpoint: "/admin/stock-location-addresses/{id}",
477
+ responseKey: "stock_location_address"
478
+ },
479
+ tax_rates: {
480
+ widgetZone: "tax_rate.details.after",
481
+ apiEndpoint: "/admin/tax-rates/{id}",
482
+ responseKey: "tax_rate"
483
+ },
484
+ tax_rate_rules: {
485
+ widgetZone: "tax_rate_rule.details.after",
486
+ apiEndpoint: "/admin/tax-rate-rules/{id}",
487
+ responseKey: "tax_rate_rule"
488
+ },
489
+ tax_regions: {
490
+ widgetZone: "tax_region.details.after",
491
+ apiEndpoint: "/admin/tax-regions/{id}",
492
+ responseKey: "tax_region"
493
+ },
494
+ users: {
495
+ widgetZone: "user.details.after",
496
+ apiEndpoint: "/admin/users/{id}",
497
+ responseKey: "user"
498
+ }
499
+ };
500
+ let customMappings = {};
501
+ function getEntityMapping(entityType) {
502
+ return customMappings[entityType] || DEFAULT_ENTITY_MAPPINGS[entityType];
503
+ }
504
+ function getApiEndpoint(entityType) {
505
+ const mapping = getEntityMapping(entityType);
506
+ return mapping == null ? void 0 : mapping.apiEndpoint;
507
+ }
508
+ function getResponseKey(entityType) {
509
+ const mapping = getEntityMapping(entityType);
510
+ return mapping == null ? void 0 : mapping.responseKey;
511
+ }
512
+ function resolveApiEndpoint(entityType, entityId) {
513
+ const endpoint = getApiEndpoint(entityType);
514
+ if (!endpoint) return void 0;
515
+ return endpoint.replace("{id}", entityId);
516
+ }
517
+ const CONFIG_DOCS_URL = "https://docs.medusajs.com/admin/extension-points/widgets";
518
+ const MetadataTableWidget = ({
519
+ data,
520
+ entityType,
521
+ queryKey = []
522
+ }) => {
523
+ const { data: descriptors = [], isPending, isError } = useMetadataConfig({
524
+ entity: entityType
525
+ });
526
+ const entityId = (data == null ? void 0 : data.id) ?? void 0;
527
+ const [baselineMetadata, setBaselineMetadata] = useState(
528
+ (data == null ? void 0 : data.metadata) ?? {}
529
+ );
530
+ const queryClient = useQueryClient();
531
+ const previousEntityIdRef = useRef(entityId);
532
+ const isInitializedRef = useRef(false);
533
+ const dataRef = useRef(data);
534
+ const descriptorsRef = useRef(descriptors);
535
+ useEffect(() => {
536
+ dataRef.current = data;
537
+ descriptorsRef.current = descriptors;
538
+ }, [data, descriptors]);
539
+ useEffect(() => {
540
+ var _a;
541
+ if (previousEntityIdRef.current === entityId && isInitializedRef.current) {
542
+ return;
543
+ }
544
+ const entityIdChanged = previousEntityIdRef.current !== entityId;
545
+ if (entityIdChanged || !isInitializedRef.current) {
546
+ const currentMetadata = (data == null ? void 0 : data.metadata) ?? ((_a = dataRef.current) == null ? void 0 : _a.metadata) ?? {};
547
+ const currentDescriptors = descriptorsRef.current.length > 0 ? descriptorsRef.current : descriptors;
548
+ if (currentDescriptors.length === 0) {
549
+ return;
550
+ }
551
+ previousEntityIdRef.current = entityId;
552
+ setBaselineMetadata(currentMetadata);
553
+ const newInitialState = buildInitialFormState(
554
+ currentDescriptors,
555
+ currentMetadata
556
+ );
557
+ setValues(newInitialState);
558
+ isInitializedRef.current = true;
559
+ }
560
+ }, [entityId]);
561
+ const metadataStringRef = useRef("");
562
+ useEffect(() => {
563
+ const hasEntityData = !!data;
564
+ const descriptorsLoaded = descriptors.length > 0;
565
+ const sameEntity = previousEntityIdRef.current === entityId;
566
+ const notInitialized = !isInitializedRef.current;
567
+ const currentMetadata = (data == null ? void 0 : data.metadata) ?? {};
568
+ const currentMetadataString = JSON.stringify(currentMetadata);
569
+ const metadataChanged = currentMetadataString !== metadataStringRef.current;
570
+ if (hasEntityData && descriptorsLoaded && sameEntity && (notInitialized || metadataChanged)) {
571
+ const newInitialState = buildInitialFormState(descriptors, currentMetadata);
572
+ setBaselineMetadata(currentMetadata);
573
+ setValues(newInitialState);
574
+ metadataStringRef.current = currentMetadataString;
575
+ isInitializedRef.current = true;
576
+ }
577
+ }, [data, descriptors.length, entityId]);
578
+ const initialState = useMemo(
579
+ () => buildInitialFormState(descriptors, baselineMetadata),
580
+ [descriptors, baselineMetadata]
581
+ );
582
+ const [values, setValues] = useState({});
583
+ const [isSaving, setIsSaving] = useState(false);
584
+ const errors = useMemo(() => {
585
+ return descriptors.reduce((acc, descriptor) => {
586
+ const error = validateValueForDescriptor(descriptor, values[descriptor.key]);
587
+ if (error) {
588
+ acc[descriptor.key] = error;
589
+ }
590
+ return acc;
591
+ }, {});
592
+ }, [descriptors, values]);
593
+ const hasErrors = Object.keys(errors).length > 0;
594
+ const isDirty = useMemo(() => {
595
+ return hasMetadataChanges({
596
+ descriptors,
597
+ values,
598
+ originalMetadata: baselineMetadata
599
+ });
600
+ }, [descriptors, values, baselineMetadata]);
601
+ const handleStringChange = (key, nextValue) => {
602
+ setValues((prev) => ({
603
+ ...prev,
604
+ [key]: nextValue
605
+ }));
606
+ };
607
+ const handleBooleanChange = (key, nextValue) => {
608
+ setValues((prev) => ({
609
+ ...prev,
610
+ [key]: nextValue
611
+ }));
612
+ };
613
+ const handleReset = () => {
614
+ setValues(initialState);
615
+ };
616
+ const handleSubmit = async () => {
617
+ if (!(data == null ? void 0 : data.id) || !descriptors.length) {
618
+ return;
619
+ }
620
+ setIsSaving(true);
621
+ try {
622
+ const metadataPayload = buildMetadataPayload({
623
+ descriptors,
624
+ values,
625
+ originalMetadata: baselineMetadata
626
+ });
627
+ const apiEndpoint = resolveApiEndpoint(entityType, data.id);
628
+ if (!apiEndpoint) {
629
+ throw new Error(`No API endpoint configured for entity type: ${entityType}`);
630
+ }
631
+ const response = await fetch(apiEndpoint, {
632
+ method: "POST",
633
+ credentials: "include",
634
+ headers: {
635
+ "Content-Type": "application/json"
636
+ },
637
+ body: JSON.stringify({
638
+ metadata: metadataPayload
639
+ })
640
+ });
641
+ if (!response.ok) {
642
+ const payload = await response.json().catch(() => null);
643
+ throw new Error((payload == null ? void 0 : payload.message) ?? "Unable to save metadata");
644
+ }
645
+ const responseKey = getResponseKey(entityType) || entityType;
646
+ const updated = await response.json();
647
+ const entity = updated[responseKey] || updated;
648
+ const nextMetadata = entity == null ? void 0 : entity.metadata;
649
+ setBaselineMetadata(nextMetadata);
650
+ setValues(buildInitialFormState(descriptors, nextMetadata));
651
+ toast.success("Metadata saved");
652
+ if (queryKey.length > 0) {
653
+ await queryClient.invalidateQueries({
654
+ queryKey
655
+ });
656
+ if (data.id) {
657
+ queryClient.refetchQueries({
658
+ queryKey: [...queryKey, data.id]
659
+ }).catch(() => {
660
+ });
661
+ }
662
+ }
663
+ } catch (error) {
664
+ toast.error(error instanceof Error ? error.message : "Save failed");
665
+ } finally {
666
+ setIsSaving(false);
667
+ }
668
+ };
669
+ return /* @__PURE__ */ jsxs(Container, { className: "flex flex-col gap-y-4", children: [
670
+ /* @__PURE__ */ jsxs("header", { className: "flex flex-col gap-y-1", children: [
671
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-3", children: [
672
+ /* @__PURE__ */ jsx(Heading, { level: "h2", children: "Metadata" }),
673
+ /* @__PURE__ */ jsx(Badge, { size: "2xsmall", rounded: "full", children: descriptors.length })
674
+ ] }),
675
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-subtle", children: "Structured metadata mapped to the keys you configured in the plugin options." })
676
+ ] }),
677
+ isPending || !isInitializedRef.current || Object.keys(values).length === 0 ? /* @__PURE__ */ jsx(Skeleton, { className: "h-[160px] w-full" }) : isError ? /* @__PURE__ */ jsxs(InlineTip, { variant: "error", label: "Configuration unavailable", children: [
678
+ "Unable to load metadata configuration for this plugin. Confirm that the plugin is registered with options in ",
679
+ /* @__PURE__ */ jsx("code", { children: "medusa-config.ts" }),
680
+ "."
681
+ ] }) : !descriptors.length ? /* @__PURE__ */ jsxs(InlineTip, { variant: "info", label: "No configured metadata keys", children: [
682
+ "Provide metadata descriptors for ",
683
+ /* @__PURE__ */ jsx("code", { children: entityType }),
684
+ " in the plugin options to control which keys show up here.",
685
+ " ",
686
+ /* @__PURE__ */ jsx(
687
+ "a",
688
+ {
689
+ className: "text-ui-fg-interactive underline",
690
+ href: CONFIG_DOCS_URL,
691
+ target: "_blank",
692
+ rel: "noreferrer",
693
+ children: "Learn how to configure it."
694
+ }
695
+ )
696
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
697
+ /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-lg border border-ui-border-base", children: /* @__PURE__ */ jsxs("table", { className: "min-w-full divide-y divide-ui-border-base", children: [
698
+ /* @__PURE__ */ jsx("thead", { className: "bg-ui-bg-subtle", children: /* @__PURE__ */ jsxs("tr", { children: [
699
+ /* @__PURE__ */ jsx(
700
+ "th",
701
+ {
702
+ scope: "col",
703
+ className: "txt-compact-xsmall-plus text-left uppercase tracking-wide text-ui-fg-muted px-4 py-3",
704
+ children: "Label"
705
+ }
706
+ ),
707
+ /* @__PURE__ */ jsx(
708
+ "th",
709
+ {
710
+ scope: "col",
711
+ className: "txt-compact-xsmall-plus text-left uppercase tracking-wide text-ui-fg-muted px-4 py-3",
712
+ children: "Value"
713
+ }
714
+ )
715
+ ] }) }),
716
+ /* @__PURE__ */ jsx("tbody", { className: "divide-y divide-ui-border-subtle bg-ui-bg-base", children: descriptors.map((descriptor) => {
717
+ const value = values[descriptor.key];
718
+ const error = errors[descriptor.key];
719
+ return /* @__PURE__ */ jsxs("tr", { children: [
720
+ /* @__PURE__ */ jsx(
721
+ "th",
722
+ {
723
+ scope: "row",
724
+ className: "txt-compact-medium text-ui-fg-base align-top px-4 py-4",
725
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-1", children: [
726
+ /* @__PURE__ */ jsx("span", { children: descriptor.label ?? descriptor.key }),
727
+ /* @__PURE__ */ jsx("span", { className: "txt-compact-xsmall-plus text-ui-fg-muted uppercase tracking-wide", children: descriptor.type })
728
+ ] })
729
+ }
730
+ ),
731
+ /* @__PURE__ */ jsx("td", { className: "align-top px-4 py-4", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-2", children: [
732
+ /* @__PURE__ */ jsx(
733
+ ValueField,
734
+ {
735
+ descriptor,
736
+ value,
737
+ onStringChange: handleStringChange,
738
+ onBooleanChange: handleBooleanChange
739
+ }
740
+ ),
741
+ error && /* @__PURE__ */ jsx(Text, { className: "txt-compact-small text-ui-fg-error", children: error })
742
+ ] }) })
743
+ ] }, descriptor.key);
744
+ }) })
745
+ ] }) }),
746
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-3 border-t border-ui-border-subtle pt-3 md:flex-row md:items-center md:justify-between", children: [
747
+ /* @__PURE__ */ jsx(Text, { className: "text-ui-fg-muted", children: "Changes are stored on the entity metadata object. Clearing a field removes the corresponding key on save." }),
748
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2", children: [
749
+ /* @__PURE__ */ jsx(
750
+ Button,
751
+ {
752
+ variant: "secondary",
753
+ size: "small",
754
+ disabled: !isDirty || isSaving,
755
+ onClick: handleReset,
756
+ children: "Reset"
757
+ }
758
+ ),
759
+ /* @__PURE__ */ jsx(
760
+ Button,
761
+ {
762
+ size: "small",
763
+ onClick: handleSubmit,
764
+ disabled: !isDirty || hasErrors || isSaving,
765
+ isLoading: isSaving,
766
+ children: "Save metadata"
767
+ }
768
+ )
769
+ ] })
770
+ ] })
771
+ ] })
772
+ ] });
773
+ };
774
+ const ValueField = ({
775
+ descriptor,
776
+ value,
777
+ onStringChange,
778
+ onBooleanChange
779
+ }) => {
780
+ const fileInputRef = useRef(null);
781
+ const [isUploading, setIsUploading] = useState(false);
782
+ const handleFileUpload = async (event) => {
783
+ var _a;
784
+ const file = (_a = event.target.files) == null ? void 0 : _a[0];
785
+ if (!file) {
786
+ return;
787
+ }
788
+ setIsUploading(true);
789
+ try {
790
+ const formData = new FormData();
791
+ formData.append("files", file);
792
+ const response = await fetch("/admin/uploads", {
793
+ method: "POST",
794
+ credentials: "include",
795
+ body: formData
796
+ });
797
+ if (!response.ok) {
798
+ const payload = await response.json().catch(() => null);
799
+ throw new Error((payload == null ? void 0 : payload.message) ?? "File upload failed");
800
+ }
801
+ const result = await response.json();
802
+ if (result.files && result.files.length > 0) {
803
+ const uploadedFile = result.files[0];
804
+ const fileUrl = uploadedFile.url || uploadedFile.key;
805
+ if (fileUrl) {
806
+ onStringChange(descriptor.key, fileUrl);
807
+ toast.success("File uploaded successfully");
808
+ } else {
809
+ throw new Error("File upload succeeded but no URL returned");
810
+ }
811
+ } else {
812
+ throw new Error("File upload failed - no files returned");
813
+ }
814
+ } catch (error) {
815
+ toast.error(
816
+ error instanceof Error ? error.message : "Failed to upload file"
817
+ );
818
+ } finally {
819
+ setIsUploading(false);
820
+ if (fileInputRef.current) {
821
+ fileInputRef.current.value = "";
822
+ }
823
+ }
824
+ };
825
+ if (descriptor.type === "bool") {
826
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2", children: [
827
+ /* @__PURE__ */ jsx(
828
+ Switch,
829
+ {
830
+ checked: Boolean(value),
831
+ onCheckedChange: (checked) => onBooleanChange(descriptor.key, Boolean(checked)),
832
+ "aria-label": `Toggle ${descriptor.label ?? descriptor.key}`
833
+ }
834
+ ),
835
+ /* @__PURE__ */ jsx(Text, { className: "txt-compact-small text-ui-fg-muted", children: Boolean(value) ? "True" : "False" })
836
+ ] });
837
+ }
838
+ if (descriptor.type === "text") {
839
+ return /* @__PURE__ */ jsx(
840
+ Textarea,
841
+ {
842
+ value: value ?? "",
843
+ placeholder: "Enter text",
844
+ rows: 3,
845
+ onChange: (event) => onStringChange(descriptor.key, event.target.value)
846
+ }
847
+ );
848
+ }
849
+ if (descriptor.type === "number") {
850
+ return /* @__PURE__ */ jsx(
851
+ Input,
852
+ {
853
+ type: "text",
854
+ inputMode: "decimal",
855
+ placeholder: "0.00",
856
+ value: value ?? "",
857
+ onChange: (event) => onStringChange(descriptor.key, event.target.value)
858
+ }
859
+ );
860
+ }
861
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-2", children: [
862
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2", children: [
863
+ /* @__PURE__ */ jsx(
864
+ Input,
865
+ {
866
+ type: "url",
867
+ placeholder: "https://example.com/file",
868
+ value: value ?? "",
869
+ onChange: (event) => onStringChange(descriptor.key, event.target.value),
870
+ className: "flex-1"
871
+ }
872
+ ),
873
+ /* @__PURE__ */ jsx(
874
+ "input",
875
+ {
876
+ ref: fileInputRef,
877
+ type: "file",
878
+ className: "hidden",
879
+ onChange: handleFileUpload,
880
+ disabled: isUploading,
881
+ "aria-label": `Upload file for ${descriptor.label ?? descriptor.key}`
882
+ }
883
+ ),
884
+ /* @__PURE__ */ jsx(
885
+ Button,
886
+ {
887
+ type: "button",
888
+ variant: "secondary",
889
+ size: "small",
890
+ onClick: () => {
891
+ var _a;
892
+ return (_a = fileInputRef.current) == null ? void 0 : _a.click();
893
+ },
894
+ disabled: isUploading,
895
+ isLoading: isUploading,
896
+ children: isUploading ? "Uploading..." : "Upload"
897
+ }
898
+ )
899
+ ] }),
900
+ typeof value === "string" && value && /* @__PURE__ */ jsx(
901
+ "a",
902
+ {
903
+ className: "txt-compact-small-plus text-ui-fg-interactive underline",
904
+ href: value,
905
+ target: "_blank",
906
+ rel: "noreferrer",
907
+ children: "View file"
908
+ }
909
+ )
910
+ ] });
911
+ };
912
+ const ZONE_PATTERNS = [
913
+ // Product zones
914
+ { pattern: /^product\.details\./, entityType: "products" },
915
+ { pattern: /^product\./, entityType: "products" },
916
+ // Order zones
917
+ { pattern: /^order\.details\./, entityType: "orders" },
918
+ { pattern: /^order\./, entityType: "orders" },
919
+ // Category zones
920
+ { pattern: /^product_category\.details\./, entityType: "categories" },
921
+ { pattern: /^product_category\./, entityType: "categories" },
922
+ { pattern: /^category\.details\./, entityType: "categories" },
923
+ { pattern: /^category\./, entityType: "categories" },
924
+ // Collection zones
925
+ { pattern: /^product_collection\.details\./, entityType: "collections" },
926
+ { pattern: /^product_collection\./, entityType: "collections" },
927
+ { pattern: /^collection\.details\./, entityType: "collections" },
928
+ { pattern: /^collection\./, entityType: "collections" },
929
+ // Customer zones
930
+ { pattern: /^customer\.details\./, entityType: "customers" },
931
+ { pattern: /^customer\./, entityType: "customers" },
932
+ // Region zones
933
+ { pattern: /^region\.details\./, entityType: "regions" },
934
+ { pattern: /^region\./, entityType: "regions" },
935
+ // Sales Channel zones
936
+ { pattern: /^sales_channel\.details\./, entityType: "sales_channels" },
937
+ { pattern: /^sales_channel\./, entityType: "sales_channels" },
938
+ // Store zones
939
+ { pattern: /^store\.details\./, entityType: "stores" },
940
+ { pattern: /^store\./, entityType: "stores" },
941
+ // Promotion zones
942
+ { pattern: /^promotion\.details\./, entityType: "promotions" },
943
+ { pattern: /^promotion\./, entityType: "promotions" },
944
+ // Campaign zones
945
+ { pattern: /^campaign\.details\./, entityType: "campaigns" },
946
+ { pattern: /^campaign\./, entityType: "campaigns" },
947
+ // Price List zones
948
+ { pattern: /^price_list\.details\./, entityType: "price_lists" },
949
+ { pattern: /^price_list\./, entityType: "price_lists" },
950
+ // Shipping Profile zones
951
+ { pattern: /^shipping_profile\.details\./, entityType: "shipping_profiles" },
952
+ { pattern: /^shipping_profile\./, entityType: "shipping_profiles" },
953
+ // Return Reason zones
954
+ { pattern: /^return_reason\.details\./, entityType: "return_reasons" },
955
+ { pattern: /^return_reason\./, entityType: "return_reasons" },
956
+ // Inventory Item zones
957
+ { pattern: /^inventory_item\.details\./, entityType: "inventory_items" },
958
+ { pattern: /^inventory_item\./, entityType: "inventory_items" },
959
+ // Product Variant zones
960
+ { pattern: /^product_variant\.details\./, entityType: "product_variants" },
961
+ { pattern: /^product_variant\./, entityType: "product_variants" },
962
+ // Account Holder zones
963
+ { pattern: /^account_holder\.details\./, entityType: "account_holders" },
964
+ { pattern: /^account_holder\./, entityType: "account_holders" },
965
+ // Capture zones
966
+ { pattern: /^capture\.details\./, entityType: "captures" },
967
+ { pattern: /^capture\./, entityType: "captures" },
968
+ // Cart zones
969
+ { pattern: /^cart\.details\./, entityType: "carts" },
970
+ { pattern: /^cart\./, entityType: "carts" },
971
+ // Cart Address zones
972
+ { pattern: /^cart_address\.details\./, entityType: "cart_addresses" },
973
+ { pattern: /^cart_address\./, entityType: "cart_addresses" },
974
+ // Cart Line Item zones
975
+ { pattern: /^cart_line_item\.details\./, entityType: "cart_line_items" },
976
+ { pattern: /^cart_line_item\./, entityType: "cart_line_items" },
977
+ // Cart Line Item Adjustment zones
978
+ { pattern: /^cart_line_item_adjustment\.details\./, entityType: "cart_line_item_adjustments" },
979
+ { pattern: /^cart_line_item_adjustment\./, entityType: "cart_line_item_adjustments" },
980
+ // Cart Line Item Tax Line zones
981
+ { pattern: /^cart_line_item_tax_line\.details\./, entityType: "cart_line_item_tax_lines" },
982
+ { pattern: /^cart_line_item_tax_line\./, entityType: "cart_line_item_tax_lines" },
983
+ // Cart Shipping Method zones
984
+ { pattern: /^cart_shipping_method\.details\./, entityType: "cart_shipping_methods" },
985
+ { pattern: /^cart_shipping_method\./, entityType: "cart_shipping_methods" },
986
+ // Cart Shipping Method Adjustment zones
987
+ { pattern: /^cart_shipping_method_adjustment\.details\./, entityType: "cart_shipping_method_adjustments" },
988
+ { pattern: /^cart_shipping_method_adjustment\./, entityType: "cart_shipping_method_adjustments" },
989
+ // Cart Shipping Method Tax Line zones
990
+ { pattern: /^cart_shipping_method_tax_line\.details\./, entityType: "cart_shipping_method_tax_lines" },
991
+ { pattern: /^cart_shipping_method_tax_line\./, entityType: "cart_shipping_method_tax_lines" },
992
+ // Contact Email Subscription zones
993
+ { pattern: /^contact_email_subscription\.details\./, entityType: "contact_email_subscriptions" },
994
+ { pattern: /^contact_email_subscription\./, entityType: "contact_email_subscriptions" },
995
+ // Contact Request zones
996
+ { pattern: /^contact_request\.details\./, entityType: "contact_requests" },
997
+ { pattern: /^contact_request\./, entityType: "contact_requests" },
998
+ // Credit Line zones
999
+ { pattern: /^credit_line\.details\./, entityType: "credit_lines" },
1000
+ { pattern: /^credit_line\./, entityType: "credit_lines" },
1001
+ // Customer Address zones
1002
+ { pattern: /^customer_address\.details\./, entityType: "customer_addresses" },
1003
+ { pattern: /^customer_address\./, entityType: "customer_addresses" },
1004
+ // Customer Group zones
1005
+ { pattern: /^customer_group\.details\./, entityType: "customer_groups" },
1006
+ { pattern: /^customer_group\./, entityType: "customer_groups" },
1007
+ // Customer Group Customer zones
1008
+ { pattern: /^customer_group_customer\.details\./, entityType: "customer_group_customers" },
1009
+ { pattern: /^customer_group_customer\./, entityType: "customer_group_customers" },
1010
+ // Fulfillment zones
1011
+ { pattern: /^fulfillment\.details\./, entityType: "fulfillments" },
1012
+ { pattern: /^fulfillment\./, entityType: "fulfillments" },
1013
+ // Fulfillment Address zones
1014
+ { pattern: /^fulfillment_address\.details\./, entityType: "fulfillment_addresses" },
1015
+ { pattern: /^fulfillment_address\./, entityType: "fulfillment_addresses" },
1016
+ // Fulfillment Set zones
1017
+ { pattern: /^fulfillment_set\.details\./, entityType: "fulfillment_sets" },
1018
+ { pattern: /^fulfillment_set\./, entityType: "fulfillment_sets" },
1019
+ // Geo Zone zones
1020
+ { pattern: /^geo_zone\.details\./, entityType: "geo_zones" },
1021
+ { pattern: /^geo_zone\./, entityType: "geo_zones" },
1022
+ // Image zones
1023
+ { pattern: /^image\.details\./, entityType: "images" },
1024
+ { pattern: /^image\./, entityType: "images" },
1025
+ // Inventory Level zones
1026
+ { pattern: /^inventory_level\.details\./, entityType: "inventory_levels" },
1027
+ { pattern: /^inventory_level\./, entityType: "inventory_levels" },
1028
+ // Invite zones
1029
+ { pattern: /^invite\.details\./, entityType: "invites" },
1030
+ { pattern: /^invite\./, entityType: "invites" },
1031
+ // Order Address zones
1032
+ { pattern: /^order_address\.details\./, entityType: "order_addresses" },
1033
+ { pattern: /^order_address\./, entityType: "order_addresses" },
1034
+ // Order Change zones
1035
+ { pattern: /^order_change\.details\./, entityType: "order_changes" },
1036
+ { pattern: /^order_change\./, entityType: "order_changes" },
1037
+ // Order Claim zones
1038
+ { pattern: /^order_claim\.details\./, entityType: "order_claims" },
1039
+ { pattern: /^order_claim\./, entityType: "order_claims" },
1040
+ // Order Claim Item zones
1041
+ { pattern: /^order_claim_item\.details\./, entityType: "order_claim_items" },
1042
+ { pattern: /^order_claim_item\./, entityType: "order_claim_items" },
1043
+ // Order Claim Item Image zones
1044
+ { pattern: /^order_claim_item_image\.details\./, entityType: "order_claim_item_images" },
1045
+ { pattern: /^order_claim_item_image\./, entityType: "order_claim_item_images" },
1046
+ // Order Credit Line zones
1047
+ { pattern: /^order_credit_line\.details\./, entityType: "order_credit_lines" },
1048
+ { pattern: /^order_credit_line\./, entityType: "order_credit_lines" },
1049
+ // Order Exchange zones
1050
+ { pattern: /^order_exchange\.details\./, entityType: "order_exchanges" },
1051
+ { pattern: /^order_exchange\./, entityType: "order_exchanges" },
1052
+ // Order Exchange Item zones
1053
+ { pattern: /^order_exchange_item\.details\./, entityType: "order_exchange_items" },
1054
+ { pattern: /^order_exchange_item\./, entityType: "order_exchange_items" },
1055
+ // Order Item zones
1056
+ { pattern: /^order_item\.details\./, entityType: "order_items" },
1057
+ { pattern: /^order_item\./, entityType: "order_items" },
1058
+ // Order Line Item zones
1059
+ { pattern: /^order_line_item\.details\./, entityType: "order_line_items" },
1060
+ { pattern: /^order_line_item\./, entityType: "order_line_items" },
1061
+ // Order Shipping Method zones
1062
+ { pattern: /^order_shipping_method\.details\./, entityType: "order_shipping_methods" },
1063
+ { pattern: /^order_shipping_method\./, entityType: "order_shipping_methods" },
1064
+ // Payment zones
1065
+ { pattern: /^payment\.details\./, entityType: "payments" },
1066
+ { pattern: /^payment\./, entityType: "payments" },
1067
+ // Payment Collection zones
1068
+ { pattern: /^payment_collection\.details\./, entityType: "payment_collections" },
1069
+ { pattern: /^payment_collection\./, entityType: "payment_collections" },
1070
+ // Payment Session zones
1071
+ { pattern: /^payment_session\.details\./, entityType: "payment_sessions" },
1072
+ { pattern: /^payment_session\./, entityType: "payment_sessions" },
1073
+ // Product Option zones
1074
+ { pattern: /^product_option\.details\./, entityType: "product_options" },
1075
+ { pattern: /^product_option\./, entityType: "product_options" },
1076
+ // Product Option Value zones
1077
+ { pattern: /^product_option_value\.details\./, entityType: "product_option_values" },
1078
+ { pattern: /^product_option_value\./, entityType: "product_option_values" },
1079
+ // Product Tag zones
1080
+ { pattern: /^product_tag\.details\./, entityType: "product_tags" },
1081
+ { pattern: /^product_tag\./, entityType: "product_tags" },
1082
+ // Product Type zones
1083
+ { pattern: /^product_type\.details\./, entityType: "product_types" },
1084
+ { pattern: /^product_type\./, entityType: "product_types" },
1085
+ // Refund zones
1086
+ { pattern: /^refund\.details\./, entityType: "refunds" },
1087
+ { pattern: /^refund\./, entityType: "refunds" },
1088
+ // Refund Reason zones
1089
+ { pattern: /^refund_reason\.details\./, entityType: "refund_reasons" },
1090
+ { pattern: /^refund_reason\./, entityType: "refund_reasons" },
1091
+ // Region Country zones
1092
+ { pattern: /^region_country\.details\./, entityType: "region_countries" },
1093
+ { pattern: /^region_country\./, entityType: "region_countries" },
1094
+ // Reservation Item zones
1095
+ { pattern: /^reservation_item\.details\./, entityType: "reservation_items" },
1096
+ { pattern: /^reservation_item\./, entityType: "reservation_items" },
1097
+ // Return zones
1098
+ { pattern: /^return\.details\./, entityType: "returns" },
1099
+ { pattern: /^return\./, entityType: "returns" },
1100
+ // Return Item zones
1101
+ { pattern: /^return_item\.details\./, entityType: "return_items" },
1102
+ { pattern: /^return_item\./, entityType: "return_items" },
1103
+ // Service Zone zones
1104
+ { pattern: /^service_zone\.details\./, entityType: "service_zones" },
1105
+ { pattern: /^service_zone\./, entityType: "service_zones" },
1106
+ // Shipping Option zones
1107
+ { pattern: /^shipping_option\.details\./, entityType: "shipping_options" },
1108
+ { pattern: /^shipping_option\./, entityType: "shipping_options" },
1109
+ // Stock Location zones
1110
+ { pattern: /^stock_location\.details\./, entityType: "stock_locations" },
1111
+ { pattern: /^stock_location\./, entityType: "stock_locations" },
1112
+ // Stock Location Address zones
1113
+ { pattern: /^stock_location_address\.details\./, entityType: "stock_location_addresses" },
1114
+ { pattern: /^stock_location_address\./, entityType: "stock_location_addresses" },
1115
+ // Tax Rate zones
1116
+ { pattern: /^tax_rate\.details\./, entityType: "tax_rates" },
1117
+ { pattern: /^tax_rate\./, entityType: "tax_rates" },
1118
+ // Tax Rate Rule zones
1119
+ { pattern: /^tax_rate_rule\.details\./, entityType: "tax_rate_rules" },
1120
+ { pattern: /^tax_rate_rule\./, entityType: "tax_rate_rules" },
1121
+ // Tax Region zones
1122
+ { pattern: /^tax_region\.details\./, entityType: "tax_regions" },
1123
+ { pattern: /^tax_region\./, entityType: "tax_regions" },
1124
+ // User zones
1125
+ { pattern: /^user\.details\./, entityType: "users" },
1126
+ { pattern: /^user\./, entityType: "users" },
1127
+ // Generic pattern: {entity}.details.{position}
1128
+ { pattern: /^(\w+)\.details\./, entityType: "" }
1129
+ // Will extract from match
1130
+ ];
1131
+ let customZoneMappings = {};
1132
+ function resolveEntityTypeFromZone(zone) {
1133
+ if (customZoneMappings[zone]) {
1134
+ return customZoneMappings[zone];
1135
+ }
1136
+ const entityTypes = [
1137
+ "products",
1138
+ "orders",
1139
+ "categories",
1140
+ "collections",
1141
+ "customers",
1142
+ "regions",
1143
+ "sales_channels",
1144
+ "stores",
1145
+ "promotions",
1146
+ "campaigns",
1147
+ "price_lists",
1148
+ "shipping_profiles",
1149
+ "return_reasons",
1150
+ "inventory_items",
1151
+ "product_variants",
1152
+ "account_holders",
1153
+ "captures",
1154
+ "carts",
1155
+ "cart_addresses",
1156
+ "cart_line_items",
1157
+ "cart_line_item_adjustments",
1158
+ "cart_line_item_tax_lines",
1159
+ "cart_shipping_methods",
1160
+ "cart_shipping_method_adjustments",
1161
+ "cart_shipping_method_tax_lines",
1162
+ "contact_email_subscriptions",
1163
+ "contact_requests",
1164
+ "credit_lines",
1165
+ "customer_addresses",
1166
+ "customer_groups",
1167
+ "customer_group_customers",
1168
+ "fulfillments",
1169
+ "fulfillment_addresses",
1170
+ "fulfillment_sets",
1171
+ "geo_zones",
1172
+ "images",
1173
+ "inventory_levels",
1174
+ "invites",
1175
+ "order_addresses",
1176
+ "order_changes",
1177
+ "order_claims",
1178
+ "order_claim_items",
1179
+ "order_claim_item_images",
1180
+ "order_credit_lines",
1181
+ "order_exchanges",
1182
+ "order_exchange_items",
1183
+ "order_items",
1184
+ "order_line_items",
1185
+ "order_shipping_methods",
1186
+ "payments",
1187
+ "payment_collections",
1188
+ "payment_sessions",
1189
+ "product_options",
1190
+ "product_option_values",
1191
+ "product_tags",
1192
+ "product_types",
1193
+ "refunds",
1194
+ "refund_reasons",
1195
+ "region_countries",
1196
+ "reservation_items",
1197
+ "returns",
1198
+ "return_items",
1199
+ "service_zones",
1200
+ "shipping_options",
1201
+ "stock_locations",
1202
+ "stock_location_addresses",
1203
+ "tax_rates",
1204
+ "tax_rate_rules",
1205
+ "tax_regions",
1206
+ "users"
1207
+ ];
1208
+ for (const entityType of entityTypes) {
1209
+ const mapping = getEntityMapping(entityType);
1210
+ if ((mapping == null ? void 0 : mapping.widgetZone) === zone) {
1211
+ return entityType;
1212
+ }
1213
+ }
1214
+ for (const { pattern, entityType } of ZONE_PATTERNS) {
1215
+ const match = zone.match(pattern);
1216
+ if (match) {
1217
+ if (entityType === "" && match[1]) {
1218
+ const singular = match[1];
1219
+ return `${singular}s`;
1220
+ }
1221
+ return entityType;
1222
+ }
1223
+ }
1224
+ const parts = zone.split(".");
1225
+ if (parts.length > 0) {
1226
+ const firstPart = parts[0];
1227
+ if (firstPart && !firstPart.endsWith("s")) {
1228
+ return `${firstPart}s`;
1229
+ }
1230
+ return firstPart;
1231
+ }
1232
+ return void 0;
1233
+ }
1234
+ const ENTITY_DETECTION_PATTERNS = [
1235
+ // Products: typically have handle, title, description
1236
+ {
1237
+ patterns: ["handle", "title", "description", "subtitle"],
1238
+ entityType: "products"
1239
+ },
1240
+ // Orders: typically have display_id, status, email
1241
+ {
1242
+ patterns: ["display_id", "status", "email", "currency_code"],
1243
+ entityType: "orders"
1244
+ },
1245
+ // Categories: typically have name, handle, parent_category_id
1246
+ {
1247
+ patterns: ["name", "handle", "parent_category_id", "category_children"],
1248
+ entityType: "categories"
1249
+ },
1250
+ // Collections: typically have title, handle
1251
+ {
1252
+ patterns: ["title", "handle", "products"],
1253
+ entityType: "collections"
1254
+ },
1255
+ // Customers: typically have email, first_name, last_name
1256
+ {
1257
+ patterns: ["email", "first_name", "last_name", "phone"],
1258
+ entityType: "customers"
1259
+ },
1260
+ // Regions: typically have name, currency_code
1261
+ {
1262
+ patterns: ["name", "currency_code", "countries"],
1263
+ entityType: "regions"
1264
+ },
1265
+ // Sales Channels: typically have name, description
1266
+ {
1267
+ patterns: ["name", "description", "is_default"],
1268
+ entityType: "sales_channels"
1269
+ },
1270
+ // Stores: typically have name, default_currency_code
1271
+ {
1272
+ patterns: ["name", "default_currency_code", "default_region_id"],
1273
+ entityType: "stores"
1274
+ },
1275
+ // Promotions: typically have code, type, is_automatic
1276
+ {
1277
+ patterns: ["code", "type", "is_automatic", "status"],
1278
+ entityType: "promotions"
1279
+ },
1280
+ // Campaigns: typically have name, campaign_identifier
1281
+ {
1282
+ patterns: ["name", "campaign_identifier", "budget"],
1283
+ entityType: "campaigns"
1284
+ },
1285
+ // Price Lists: typically have name, type, status
1286
+ {
1287
+ patterns: ["name", "type", "status", "prices"],
1288
+ entityType: "price_lists"
1289
+ },
1290
+ // Shipping Profiles: typically have name, type
1291
+ {
1292
+ patterns: ["name", "type", "shipping_options"],
1293
+ entityType: "shipping_profiles"
1294
+ },
1295
+ // Return Reasons: typically have label, value
1296
+ {
1297
+ patterns: ["label", "value", "description"],
1298
+ entityType: "return_reasons"
1299
+ },
1300
+ // Inventory Items: typically have sku, requires_shipping
1301
+ {
1302
+ patterns: ["sku", "requires_shipping", "hs_code"],
1303
+ entityType: "inventory_items"
1304
+ },
1305
+ // Product Variants: typically have sku, title, inventory_quantity
1306
+ {
1307
+ patterns: ["sku", "title", "inventory_quantity", "manage_inventory"],
1308
+ entityType: "product_variants"
1309
+ },
1310
+ // Carts: typically have email, region_id, currency_code
1311
+ {
1312
+ patterns: ["email", "region_id", "currency_code", "items"],
1313
+ entityType: "carts"
1314
+ },
1315
+ // Payments: typically have amount, currency_code, provider_id
1316
+ {
1317
+ patterns: ["amount", "currency_code", "provider_id", "status"],
1318
+ entityType: "payments"
1319
+ },
1320
+ // Fulfillments: typically have location_id, provider_id, shipped_at
1321
+ {
1322
+ patterns: ["location_id", "provider_id", "shipped_at", "delivered_at"],
1323
+ entityType: "fulfillments"
1324
+ },
1325
+ // Returns: typically have order_id, status, items
1326
+ {
1327
+ patterns: ["order_id", "status", "items", "return_reason"],
1328
+ entityType: "returns"
1329
+ },
1330
+ // Refunds: typically have amount, currency_code, reason
1331
+ {
1332
+ patterns: ["amount", "currency_code", "reason", "payment_id"],
1333
+ entityType: "refunds"
1334
+ },
1335
+ // Customer Groups: typically have name, customers
1336
+ {
1337
+ patterns: ["name", "customers", "created_at"],
1338
+ entityType: "customer_groups"
1339
+ },
1340
+ // Shipping Options: typically have name, price_type, service_zone_id
1341
+ {
1342
+ patterns: ["name", "price_type", "service_zone_id", "shipping_profile_id"],
1343
+ entityType: "shipping_options"
1344
+ },
1345
+ // Tax Rates: typically have rate, code, name
1346
+ {
1347
+ patterns: ["rate", "code", "name", "region_id"],
1348
+ entityType: "tax_rates"
1349
+ },
1350
+ // Users: typically have email, first_name, last_name
1351
+ {
1352
+ patterns: ["email", "first_name", "last_name", "role"],
1353
+ entityType: "users"
1354
+ }
1355
+ ];
1356
+ function detectEntityTypeFromData(data) {
1357
+ if (!data || typeof data !== "object") {
1358
+ return void 0;
1359
+ }
1360
+ const dataKeys = Object.keys(data);
1361
+ const scores = {};
1362
+ for (const { patterns, entityType } of ENTITY_DETECTION_PATTERNS) {
1363
+ const matchCount = patterns.filter((pattern) => dataKeys.includes(pattern)).length;
1364
+ if (matchCount > 0) {
1365
+ scores[entityType] = matchCount;
1366
+ }
1367
+ }
1368
+ const sortedScores = Object.entries(scores).sort((a, b) => b[1] - a[1]);
1369
+ if (sortedScores.length > 0 && sortedScores[0][1] > 0) {
1370
+ return sortedScores[0][0];
1371
+ }
1372
+ return void 0;
1373
+ }
1374
+ function resolveQueryKey(entityType) {
1375
+ const queryKeyMap = {
1376
+ products: ["products"],
1377
+ orders: ["orders"],
1378
+ categories: ["product-categories"],
1379
+ collections: ["collections"],
1380
+ customers: ["customers"],
1381
+ regions: ["regions"],
1382
+ sales_channels: ["sales-channels"],
1383
+ stores: ["stores"],
1384
+ promotions: ["promotions"],
1385
+ campaigns: ["campaigns"],
1386
+ price_lists: ["price-lists"],
1387
+ shipping_profiles: ["shipping-profiles"],
1388
+ return_reasons: ["return-reasons"],
1389
+ inventory_items: ["inventory-items"],
1390
+ product_variants: ["product-variants"],
1391
+ account_holders: ["account-holders"],
1392
+ captures: ["captures"],
1393
+ carts: ["carts"],
1394
+ cart_addresses: ["cart-addresses"],
1395
+ cart_line_items: ["cart-line-items"],
1396
+ cart_line_item_adjustments: ["cart-line-item-adjustments"],
1397
+ cart_line_item_tax_lines: ["cart-line-item-tax-lines"],
1398
+ cart_shipping_methods: ["cart-shipping-methods"],
1399
+ cart_shipping_method_adjustments: ["cart-shipping-method-adjustments"],
1400
+ cart_shipping_method_tax_lines: ["cart-shipping-method-tax-lines"],
1401
+ contact_email_subscriptions: ["contact-email-subscriptions"],
1402
+ contact_requests: ["contact-requests"],
1403
+ credit_lines: ["credit-lines"],
1404
+ customer_addresses: ["customer-addresses"],
1405
+ customer_groups: ["customer-groups"],
1406
+ customer_group_customers: ["customer-group-customers"],
1407
+ fulfillments: ["fulfillments"],
1408
+ fulfillment_addresses: ["fulfillment-addresses"],
1409
+ fulfillment_sets: ["fulfillment-sets"],
1410
+ geo_zones: ["geo-zones"],
1411
+ images: ["images"],
1412
+ inventory_levels: ["inventory-levels"],
1413
+ invites: ["invites"],
1414
+ order_addresses: ["order-addresses"],
1415
+ order_changes: ["order-changes"],
1416
+ order_claims: ["order-claims"],
1417
+ order_claim_items: ["order-claim-items"],
1418
+ order_claim_item_images: ["order-claim-item-images"],
1419
+ order_credit_lines: ["order-credit-lines"],
1420
+ order_exchanges: ["order-exchanges"],
1421
+ order_exchange_items: ["order-exchange-items"],
1422
+ order_items: ["order-items"],
1423
+ order_line_items: ["order-line-items"],
1424
+ order_shipping_methods: ["order-shipping-methods"],
1425
+ payments: ["payments"],
1426
+ payment_collections: ["payment-collections"],
1427
+ payment_sessions: ["payment-sessions"],
1428
+ product_options: ["product-options"],
1429
+ product_option_values: ["product-option-values"],
1430
+ product_tags: ["product-tags"],
1431
+ product_types: ["product-types"],
1432
+ refunds: ["refunds"],
1433
+ refund_reasons: ["refund-reasons"],
1434
+ region_countries: ["region-countries"],
1435
+ reservation_items: ["reservation-items"],
1436
+ returns: ["returns"],
1437
+ return_items: ["return-items"],
1438
+ service_zones: ["service-zones"],
1439
+ shipping_options: ["shipping-options"],
1440
+ stock_locations: ["stock-locations"],
1441
+ stock_location_addresses: ["stock-location-addresses"],
1442
+ tax_rates: ["tax-rates"],
1443
+ tax_rate_rules: ["tax-rate-rules"],
1444
+ tax_regions: ["tax-regions"],
1445
+ users: ["users"]
1446
+ };
1447
+ return queryKeyMap[entityType] || [entityType];
1448
+ }
1449
+ const UniversalMetadataWidget = ({
1450
+ data,
1451
+ zone
1452
+ }) => {
1453
+ const entityType = useMemo(() => {
1454
+ if (zone) {
1455
+ const zoneResolved = resolveEntityTypeFromZone(zone);
1456
+ if (zoneResolved) {
1457
+ return zoneResolved;
1458
+ }
1459
+ }
1460
+ if (data) {
1461
+ const dataDetected = detectEntityTypeFromData(data);
1462
+ if (dataDetected) {
1463
+ return dataDetected;
1464
+ }
1465
+ }
1466
+ console.warn(
1467
+ "[UniversalMetadataWidget] Could not detect entity type. Using default: products",
1468
+ { zone, dataKeys: data ? Object.keys(data) : [] }
1469
+ );
1470
+ return "products";
1471
+ }, [zone, data]);
1472
+ const { data: descriptors = [], isPending } = useMetadataConfig({
1473
+ entity: entityType
1474
+ });
1475
+ if (!isPending && descriptors.length === 0) {
1476
+ return null;
1477
+ }
1478
+ const queryKey = useMemo(() => {
1479
+ return resolveQueryKey(entityType);
1480
+ }, [entityType]);
1481
+ return /* @__PURE__ */ jsx(
1482
+ MetadataTableWidget,
1483
+ {
1484
+ data,
1485
+ entityType,
1486
+ queryKey
1487
+ }
1488
+ );
1489
+ };
1490
+ const Widget$d = ({ data }) => {
1491
+ return /* @__PURE__ */ jsx(UniversalMetadataWidget, { data, zone: "campaign.details.after" });
1492
+ };
1493
+ defineWidgetConfig({
1494
+ zone: "campaign.details.after"
1495
+ });
1496
+ const Widget$c = ({ data }) => {
1497
+ return /* @__PURE__ */ jsx(UniversalMetadataWidget, { data, zone: "product_category.details.after" });
1498
+ };
1499
+ defineWidgetConfig({
1500
+ zone: "product_category.details.after"
1501
+ });
1502
+ const Widget$b = ({ data }) => {
1503
+ return /* @__PURE__ */ jsx(UniversalMetadataWidget, { data, zone: "product_collection.details.after" });
1504
+ };
1505
+ defineWidgetConfig({
1506
+ zone: "product_collection.details.after"
1507
+ });
1508
+ const Widget$a = ({ data }) => {
1509
+ return /* @__PURE__ */ jsx(UniversalMetadataWidget, { data, zone: "customer.details.after" });
1510
+ };
1511
+ defineWidgetConfig({
1512
+ zone: "customer.details.after"
1513
+ });
1514
+ const GenericMetadataTableWidget = ({ data }) => {
1515
+ return /* @__PURE__ */ jsx(
1516
+ UniversalMetadataWidget,
1517
+ {
1518
+ data,
1519
+ zone: "product.details.after"
1520
+ }
1521
+ );
1522
+ };
1523
+ defineWidgetConfig({
1524
+ zone: "product.details.after"
1525
+ // TODO: Replace with your entity's zone (e.g., "customer.details.after")
1526
+ });
1527
+ const HideDefaultMetadataWidget = () => {
1528
+ useEffect(() => {
1529
+ const hideMetadataSection = () => {
1530
+ const headings = document.querySelectorAll("h2");
1531
+ headings.forEach((heading) => {
1532
+ var _a;
1533
+ if (((_a = heading.textContent) == null ? void 0 : _a.trim()) === "Metadata") {
1534
+ let container = heading.parentElement;
1535
+ while (container && container !== document.body) {
1536
+ const hasContainerClass = container.classList.toString().includes("Container");
1537
+ const isInSidebar = container.closest('[class*="Sidebar"]') || container.closest('[class*="sidebar"]');
1538
+ if (hasContainerClass || isInSidebar) {
1539
+ const editLink = container.querySelector('a[href*="metadata/edit"]');
1540
+ const badge = container.querySelector('div[class*="Badge"]');
1541
+ if (editLink && badge) {
1542
+ container.style.display = "none";
1543
+ container.setAttribute("data-metadata-hidden", "true");
1544
+ return;
1545
+ }
1546
+ }
1547
+ container = container.parentElement;
1548
+ }
1549
+ }
1550
+ });
1551
+ };
1552
+ const runHide = () => {
1553
+ setTimeout(hideMetadataSection, 100);
1554
+ };
1555
+ runHide();
1556
+ const observer = new MutationObserver(() => {
1557
+ const alreadyHidden = document.querySelector('[data-metadata-hidden="true"]');
1558
+ if (!alreadyHidden) {
1559
+ runHide();
1560
+ }
1561
+ });
1562
+ observer.observe(document.body, {
1563
+ childList: true,
1564
+ subtree: true
1565
+ });
1566
+ return () => {
1567
+ observer.disconnect();
1568
+ const hidden = document.querySelector('[data-metadata-hidden="true"]');
1569
+ if (hidden) {
1570
+ hidden.style.display = "";
1571
+ hidden.removeAttribute("data-metadata-hidden");
1572
+ }
1573
+ };
1574
+ }, []);
1575
+ return null;
1576
+ };
1577
+ const ProductHideDefaultMetadata = () => {
1578
+ return /* @__PURE__ */ jsx(HideDefaultMetadataWidget, {});
1579
+ };
1580
+ defineWidgetConfig({
1581
+ zone: "product.details.side.before"
1582
+ });
1583
+ const Widget$9 = ({ data }) => {
1584
+ return /* @__PURE__ */ jsx(UniversalMetadataWidget, { data, zone: "inventory_item.details.after" });
1585
+ };
1586
+ defineWidgetConfig({
1587
+ zone: "inventory_item.details.after"
1588
+ });
1589
+ const Widget$8 = ({ data }) => {
1590
+ return /* @__PURE__ */ jsx(UniversalMetadataWidget, { data, zone: "order.details.after" });
1591
+ };
1592
+ defineWidgetConfig({
1593
+ zone: "order.details.after"
1594
+ });
1595
+ const Widget$7 = ({ data }) => {
1596
+ return /* @__PURE__ */ jsx(UniversalMetadataWidget, { data, zone: "price_list.details.after" });
1597
+ };
1598
+ defineWidgetConfig({
1599
+ zone: "price_list.details.after"
1600
+ });
1601
+ const Widget$6 = ({ data }) => {
1602
+ return /* @__PURE__ */ jsx(UniversalMetadataWidget, { data, zone: "product_variant.details.after" });
1603
+ };
1604
+ defineWidgetConfig({
1605
+ zone: "product_variant.details.after"
1606
+ });
1607
+ const Widget$5 = ({ data }) => {
1608
+ return /* @__PURE__ */ jsx(UniversalMetadataWidget, { data, zone: "product.details.after" });
1609
+ };
1610
+ defineWidgetConfig({
1611
+ zone: "product.details.after"
1612
+ });
1613
+ const Widget$4 = ({ data }) => {
1614
+ return /* @__PURE__ */ jsx(UniversalMetadataWidget, { data, zone: "promotion.details.after" });
1615
+ };
1616
+ defineWidgetConfig({
1617
+ zone: "promotion.details.after"
1618
+ });
1619
+ const Widget$3 = ({ data }) => {
1620
+ return /* @__PURE__ */ jsx(UniversalMetadataWidget, { data, zone: "region.details.after" });
1621
+ };
1622
+ defineWidgetConfig({
1623
+ zone: "region.details.after"
1624
+ });
1625
+ const Widget$2 = ({ data }) => {
1626
+ return /* @__PURE__ */ jsx(UniversalMetadataWidget, { data, zone: "sales_channel.details.after" });
1627
+ };
1628
+ defineWidgetConfig({
1629
+ zone: "sales_channel.details.after"
1630
+ });
1631
+ const Widget$1 = ({ data }) => {
1632
+ return /* @__PURE__ */ jsx(UniversalMetadataWidget, { data, zone: "shipping_profile.details.after" });
1633
+ };
1634
+ defineWidgetConfig({
1635
+ zone: "shipping_profile.details.after"
1636
+ });
1637
+ const Widget = ({ data }) => {
1638
+ return /* @__PURE__ */ jsx(UniversalMetadataWidget, { data, zone: "store.details.after" });
1639
+ };
1640
+ defineWidgetConfig({
1641
+ zone: "store.details.after"
1642
+ });
1643
+ const widgetModule = { widgets: [
1644
+ {
1645
+ Component: Widget$d,
1646
+ zone: ["campaign.details.after"]
1647
+ },
1648
+ {
1649
+ Component: Widget$c,
1650
+ zone: ["product_category.details.after"]
1651
+ },
1652
+ {
1653
+ Component: Widget$b,
1654
+ zone: ["product_collection.details.after"]
1655
+ },
1656
+ {
1657
+ Component: Widget$a,
1658
+ zone: ["customer.details.after"]
1659
+ },
1660
+ {
1661
+ Component: GenericMetadataTableWidget,
1662
+ zone: ["product.details.after"]
1663
+ },
1664
+ {
1665
+ Component: ProductHideDefaultMetadata,
1666
+ zone: ["product.details.side.before"]
1667
+ },
1668
+ {
1669
+ Component: Widget$9,
1670
+ zone: ["inventory_item.details.after"]
1671
+ },
1672
+ {
1673
+ Component: Widget$8,
1674
+ zone: ["order.details.after"]
1675
+ },
1676
+ {
1677
+ Component: Widget$7,
1678
+ zone: ["price_list.details.after"]
1679
+ },
1680
+ {
1681
+ Component: Widget$6,
1682
+ zone: ["product_variant.details.after"]
1683
+ },
1684
+ {
1685
+ Component: Widget$5,
1686
+ zone: ["product.details.after"]
1687
+ },
1688
+ {
1689
+ Component: Widget$4,
1690
+ zone: ["promotion.details.after"]
1691
+ },
1692
+ {
1693
+ Component: Widget$3,
1694
+ zone: ["region.details.after"]
1695
+ },
1696
+ {
1697
+ Component: Widget$2,
1698
+ zone: ["sales_channel.details.after"]
1699
+ },
1700
+ {
1701
+ Component: Widget$1,
1702
+ zone: ["shipping_profile.details.after"]
1703
+ },
1704
+ {
1705
+ Component: Widget,
1706
+ zone: ["store.details.after"]
1707
+ }
1708
+ ] };
1709
+ const routeModule = {
1710
+ routes: []
1711
+ };
1712
+ const menuItemModule = {
1713
+ menuItems: []
1714
+ };
1715
+ const formModule = { customFields: {} };
1716
+ const displayModule = {
1717
+ displays: {}
1718
+ };
1719
+ const i18nModule = { resources: {} };
1720
+ const plugin = {
1721
+ widgetModule,
1722
+ routeModule,
1723
+ menuItemModule,
1724
+ formModule,
1725
+ displayModule,
1726
+ i18nModule
1727
+ };
1728
+ export {
1729
+ plugin as default
1730
+ };