@vendure/dashboard 3.4.0-minor-202506250934 → 3.4.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.
- package/README.md +102 -3
- package/dist/plugin/api/api-extensions.d.ts +1 -0
- package/dist/plugin/api/api-extensions.js +38 -0
- package/dist/plugin/api/metrics.resolver.d.ts +8 -0
- package/dist/plugin/api/metrics.resolver.js +40 -0
- package/dist/plugin/config/metrics-strategies.d.ts +39 -0
- package/dist/plugin/config/metrics-strategies.js +74 -0
- package/dist/plugin/constants.d.ts +4 -3
- package/dist/plugin/constants.js +10 -277
- package/dist/plugin/dashboard.plugin.d.ts +95 -0
- package/dist/plugin/dashboard.plugin.js +168 -0
- package/dist/plugin/index.d.ts +2 -1
- package/dist/plugin/index.js +18 -1
- package/dist/plugin/package.json +3 -0
- package/dist/plugin/service/metrics.service.d.ts +15 -0
- package/dist/plugin/service/metrics.service.js +145 -0
- package/dist/plugin/types.d.ts +23 -0
- package/dist/plugin/types.js +13 -0
- package/dist/vite/constants.d.ts +5 -0
- package/dist/vite/constants.js +277 -0
- package/dist/vite/index.d.ts +1 -0
- package/dist/vite/index.js +1 -0
- package/dist/vite/types.d.ts +40 -0
- package/dist/{plugin → vite}/utils/ast-utils.d.ts +0 -5
- package/dist/vite/utils/ast-utils.js +29 -0
- package/dist/vite/utils/ast-utils.spec.d.ts +1 -0
- package/dist/vite/utils/ast-utils.spec.js +45 -0
- package/dist/vite/utils/compiler.d.ts +22 -0
- package/dist/vite/utils/compiler.js +162 -0
- package/dist/vite/utils/config-loader.d.ts +1 -0
- package/dist/vite/utils/config-loader.js +1 -0
- package/dist/vite/utils/logger.d.ts +3 -0
- package/dist/vite/utils/logger.js +39 -0
- package/dist/vite/utils/plugin-discovery.d.ts +27 -0
- package/dist/vite/utils/plugin-discovery.js +387 -0
- package/dist/vite/utils/tsconfig-utils.d.ts +9 -0
- package/dist/vite/utils/tsconfig-utils.js +50 -0
- package/dist/vite/utils/ui-config.d.ts +3 -0
- package/dist/vite/utils/ui-config.js +30 -0
- package/dist/{plugin → vite}/vite-plugin-config-loader.d.ts +3 -3
- package/dist/{plugin → vite}/vite-plugin-config-loader.js +18 -13
- package/dist/{plugin → vite}/vite-plugin-config.js +6 -7
- package/dist/{plugin → vite}/vite-plugin-dashboard-metadata.d.ts +1 -3
- package/dist/{plugin → vite}/vite-plugin-dashboard-metadata.js +20 -10
- package/dist/vite/vite-plugin-tailwind-source.d.ts +7 -0
- package/dist/vite/vite-plugin-tailwind-source.js +61 -0
- package/dist/vite/vite-plugin-theme.js +130 -0
- package/dist/vite/vite-plugin-ui-config.d.ts +123 -0
- package/dist/{plugin → vite}/vite-plugin-ui-config.js +3 -11
- package/dist/vite/vite-plugin-vendure-dashboard.d.ts +85 -0
- package/dist/{plugin → vite}/vite-plugin-vendure-dashboard.js +10 -7
- package/index.html +1 -1
- package/package.json +56 -31
- package/src/app/app-providers.tsx +7 -7
- package/src/app/common/delete-bulk-action.tsx +148 -0
- package/src/app/common/duplicate-bulk-action.tsx +134 -0
- package/src/app/main.tsx +9 -9
- package/src/app/routes/__root.tsx +1 -2
- package/src/app/routes/_authenticated/_administrators/administrators.graphql.ts +10 -1
- package/src/app/routes/_authenticated/_administrators/administrators.tsx +15 -8
- package/src/app/routes/_authenticated/_administrators/administrators_.$id.tsx +16 -12
- package/src/app/routes/_authenticated/_administrators/components/administrator-bulk-actions.tsx +15 -0
- package/src/app/routes/_authenticated/_administrators/components/role-permissions-display.tsx +16 -16
- package/src/app/routes/_authenticated/_assets/assets.graphql.ts +13 -2
- package/src/app/routes/_authenticated/_assets/assets.tsx +16 -4
- package/src/app/routes/_authenticated/_assets/assets_.$id.tsx +52 -38
- package/src/app/routes/_authenticated/_assets/components/asset-bulk-actions.tsx +45 -0
- package/src/app/routes/_authenticated/_channels/channels.graphql.ts +10 -1
- package/src/app/routes/_authenticated/_channels/channels.tsx +17 -10
- package/src/app/routes/_authenticated/_channels/channels_.$id.tsx +21 -17
- package/src/app/routes/_authenticated/_channels/components/channel-bulk-actions.tsx +15 -0
- package/src/app/routes/_authenticated/_collections/collections.graphql.ts +60 -3
- package/src/app/routes/_authenticated/_collections/collections.tsx +168 -124
- package/src/app/routes/_authenticated/_collections/collections_.$id.tsx +21 -17
- package/src/app/routes/_authenticated/_collections/components/collection-bulk-actions.tsx +123 -0
- package/src/app/routes/_authenticated/_collections/components/collection-contents-preview-table.tsx +8 -9
- package/src/app/routes/_authenticated/_collections/components/collection-contents-sheet.tsx +9 -5
- package/src/app/routes/_authenticated/_collections/components/collection-contents-table.tsx +10 -9
- package/src/app/routes/_authenticated/_collections/components/collection-filters-selector.tsx +12 -79
- package/src/app/routes/_authenticated/_collections/components/move-collections-dialog.tsx +430 -0
- package/src/app/routes/_authenticated/_collections/components/move-single-collection.tsx +33 -0
- package/src/app/routes/_authenticated/_countries/components/country-bulk-actions.tsx +15 -0
- package/src/app/routes/_authenticated/_countries/countries.graphql.ts +11 -2
- package/src/app/routes/_authenticated/_countries/countries.tsx +13 -6
- package/src/app/routes/_authenticated/_countries/countries_.$id.tsx +21 -17
- package/src/app/routes/_authenticated/_customer-groups/components/customer-group-bulk-actions.tsx +15 -0
- package/src/app/routes/_authenticated/_customer-groups/components/customer-group-members-sheet.tsx +12 -5
- package/src/app/routes/_authenticated/_customer-groups/components/customer-group-members-table.tsx +22 -17
- package/src/app/routes/_authenticated/_customer-groups/customer-groups.graphql.ts +11 -2
- package/src/app/routes/_authenticated/_customer-groups/customer-groups.tsx +13 -6
- package/src/app/routes/_authenticated/_customer-groups/customer-groups_.$id.tsx +18 -15
- package/src/app/routes/_authenticated/_customers/components/customer-address-card.tsx +19 -19
- package/src/app/routes/_authenticated/_customers/components/customer-address-form.tsx +10 -10
- package/src/app/routes/_authenticated/_customers/components/customer-bulk-actions.tsx +15 -0
- package/src/app/routes/_authenticated/_customers/components/customer-history/customer-history-container.tsx +5 -5
- package/src/app/routes/_authenticated/_customers/components/customer-history/customer-history.tsx +11 -7
- package/src/app/routes/_authenticated/_customers/components/customer-history/use-customer-history.ts +4 -4
- package/src/app/routes/_authenticated/_customers/components/customer-order-table.tsx +75 -73
- package/src/app/routes/_authenticated/_customers/components/customer-status-badge.tsx +4 -4
- package/src/app/routes/_authenticated/_customers/customers.graphql.ts +10 -2
- package/src/app/routes/_authenticated/_customers/customers.tsx +13 -6
- package/src/app/routes/_authenticated/_customers/customers_.$id.tsx +19 -15
- package/src/app/routes/_authenticated/_facets/components/edit-facet-value.tsx +9 -9
- package/src/app/routes/_authenticated/_facets/components/facet-bulk-actions.tsx +104 -0
- package/src/app/routes/_authenticated/_facets/components/facet-values-sheet.tsx +4 -4
- package/src/app/routes/_authenticated/_facets/components/facet-values-table.tsx +76 -65
- package/src/app/routes/_authenticated/_facets/facets.graphql.ts +80 -1
- package/src/app/routes/_authenticated/_facets/facets.tsx +31 -7
- package/src/app/routes/_authenticated/_facets/facets_.$facetId.values_.$id.tsx +147 -0
- package/src/app/routes/_authenticated/_facets/facets_.$id.tsx +17 -13
- package/src/app/routes/_authenticated/_global-settings/global-settings.graphql.ts +1 -1
- package/src/app/routes/_authenticated/_global-settings/global-settings.tsx +26 -18
- package/src/app/routes/_authenticated/_orders/components/add-manual-payment-dialog.tsx +191 -0
- package/src/app/routes/_authenticated/_orders/components/customer-address-selector.tsx +11 -15
- package/src/app/routes/_authenticated/_orders/components/edit-order-table.tsx +111 -80
- package/src/app/routes/_authenticated/_orders/components/fulfill-order-dialog.tsx +320 -0
- package/src/app/routes/_authenticated/_orders/components/fulfillment-details.tsx +153 -0
- package/src/app/routes/_authenticated/_orders/components/money-gross-net.tsx +11 -9
- package/src/app/routes/_authenticated/_orders/components/order-address.tsx +19 -13
- package/src/app/routes/_authenticated/_orders/components/order-history/order-history-container.tsx +67 -62
- package/src/app/routes/_authenticated/_orders/components/order-history/order-history.tsx +391 -39
- package/src/app/routes/_authenticated/_orders/components/order-history/use-order-history.ts +9 -5
- package/src/app/routes/_authenticated/_orders/components/order-line-custom-fields-form.tsx +28 -13
- package/src/app/routes/_authenticated/_orders/components/order-modification-preview-dialog.tsx +364 -0
- package/src/app/routes/_authenticated/_orders/components/order-modification-summary.tsx +222 -0
- package/src/app/routes/_authenticated/_orders/components/order-table-totals.tsx +39 -22
- package/src/app/routes/_authenticated/_orders/components/order-table.tsx +148 -87
- package/src/app/routes/_authenticated/_orders/components/order-tax-summary.tsx +37 -36
- package/src/app/routes/_authenticated/_orders/components/payment-details.tsx +274 -48
- package/src/app/routes/_authenticated/_orders/components/settle-refund-dialog.tsx +80 -0
- package/src/app/routes/_authenticated/_orders/components/shipping-method-selector.tsx +43 -44
- package/src/app/routes/_authenticated/_orders/components/state-transition-control.tsx +102 -0
- package/src/app/routes/_authenticated/_orders/components/use-transition-order-to-state.tsx +144 -0
- package/src/app/routes/_authenticated/_orders/orders.graphql.ts +219 -5
- package/src/app/routes/_authenticated/_orders/orders.tsx +23 -22
- package/src/app/routes/_authenticated/_orders/orders_.$id.tsx +190 -42
- package/src/app/routes/_authenticated/_orders/orders_.$id_.modify.tsx +550 -0
- package/src/app/routes/_authenticated/_orders/orders_.draft.$id.tsx +187 -107
- package/src/app/routes/_authenticated/_orders/utils/order-types.ts +10 -0
- package/src/app/routes/_authenticated/_orders/utils/order-utils.ts +78 -0
- package/src/app/routes/_authenticated/_payment-methods/components/payment-eligibility-checker-selector.tsx +12 -79
- package/src/app/routes/_authenticated/_payment-methods/components/payment-handler-selector.tsx +12 -79
- package/src/app/routes/_authenticated/_payment-methods/components/payment-method-bulk-actions.tsx +58 -0
- package/src/app/routes/_authenticated/_payment-methods/payment-methods.graphql.ts +29 -2
- package/src/app/routes/_authenticated/_payment-methods/payment-methods.tsx +36 -14
- package/src/app/routes/_authenticated/_payment-methods/payment-methods_.$id.tsx +22 -15
- package/src/app/routes/_authenticated/_product-variants/components/product-variant-bulk-actions.tsx +110 -0
- package/src/app/routes/_authenticated/_product-variants/components/variant-price-detail.tsx +7 -6
- package/src/app/routes/_authenticated/_product-variants/product-variants.graphql.ts +64 -3
- package/src/app/routes/_authenticated/_product-variants/product-variants.tsx +39 -9
- package/src/app/routes/_authenticated/_product-variants/product-variants_.$id.tsx +33 -22
- package/src/app/routes/_authenticated/_products/components/add-product-variant-dialog.tsx +10 -10
- package/src/app/routes/_authenticated/_products/components/assign-facet-values-dialog.tsx +281 -0
- package/src/app/routes/_authenticated/_products/components/create-product-options-dialog.tsx +57 -41
- package/src/app/routes/_authenticated/_products/components/create-product-variants-dialog.tsx +11 -11
- package/src/app/routes/_authenticated/_products/components/create-product-variants.tsx +18 -14
- package/src/app/routes/_authenticated/_products/components/option-value-input.tsx +23 -17
- package/src/app/routes/_authenticated/_products/components/product-bulk-actions.tsx +123 -0
- package/src/app/routes/_authenticated/_products/components/product-option-select.tsx +28 -34
- package/src/app/routes/_authenticated/_products/components/product-variants-table.tsx +84 -53
- package/src/app/routes/_authenticated/_products/products.graphql.ts +70 -2
- package/src/app/routes/_authenticated/_products/products.tsx +36 -7
- package/src/app/routes/_authenticated/_products/products_.$id.tsx +34 -26
- package/src/app/routes/_authenticated/_profile/profile.graphql.ts +1 -1
- package/src/app/routes/_authenticated/_profile/profile.tsx +8 -8
- package/src/app/routes/_authenticated/_promotions/components/promotion-actions-selector.tsx +14 -86
- package/src/app/routes/_authenticated/_promotions/components/promotion-bulk-actions.tsx +82 -0
- package/src/app/routes/_authenticated/_promotions/components/promotion-conditions-selector.tsx +14 -86
- package/src/app/routes/_authenticated/_promotions/promotions.graphql.ts +27 -2
- package/src/app/routes/_authenticated/_promotions/promotions.tsx +31 -7
- package/src/app/routes/_authenticated/_promotions/promotions_.$id.tsx +20 -16
- package/src/app/routes/_authenticated/_roles/components/expandable-permissions.tsx +5 -5
- package/src/app/routes/_authenticated/_roles/components/permissions-grid.tsx +21 -17
- package/src/app/routes/_authenticated/_roles/components/role-bulk-actions.tsx +15 -0
- package/src/app/routes/_authenticated/_roles/roles.graphql.ts +10 -1
- package/src/app/routes/_authenticated/_roles/roles.tsx +17 -10
- package/src/app/routes/_authenticated/_roles/roles_.$id.tsx +16 -12
- package/src/app/routes/_authenticated/_sellers/components/seller-bulk-actions.tsx +15 -0
- package/src/app/routes/_authenticated/_sellers/sellers.graphql.ts +10 -1
- package/src/app/routes/_authenticated/_sellers/sellers.tsx +13 -6
- package/src/app/routes/_authenticated/_sellers/sellers_.$id.tsx +17 -13
- package/src/app/routes/_authenticated/_shipping-methods/components/fulfillment-handler-selector.tsx +6 -6
- package/src/app/routes/_authenticated/_shipping-methods/components/shipping-calculator-selector.tsx +12 -80
- package/src/app/routes/_authenticated/_shipping-methods/components/shipping-eligibility-checker-selector.tsx +15 -80
- package/src/app/routes/_authenticated/_shipping-methods/components/shipping-method-bulk-actions.tsx +61 -0
- package/src/app/routes/_authenticated/_shipping-methods/components/test-shipping-method-dialog.tsx +3 -3
- package/src/app/routes/_authenticated/_shipping-methods/shipping-methods.graphql.ts +29 -2
- package/src/app/routes/_authenticated/_shipping-methods/shipping-methods.tsx +25 -6
- package/src/app/routes/_authenticated/_shipping-methods/shipping-methods_.$id.tsx +25 -19
- package/src/app/routes/_authenticated/_stock-locations/components/stock-location-bulk-actions.tsx +58 -0
- package/src/app/routes/_authenticated/_stock-locations/stock-locations.graphql.ts +26 -1
- package/src/app/routes/_authenticated/_stock-locations/stock-locations.tsx +25 -6
- package/src/app/routes/_authenticated/_stock-locations/stock-locations_.$id.tsx +16 -12
- package/src/app/routes/_authenticated/_system/components/payload-dialog.tsx +5 -5
- package/src/app/routes/_authenticated/_system/healthchecks.tsx +5 -5
- package/src/app/routes/_authenticated/_system/job-queue.graphql.ts +12 -1
- package/src/app/routes/_authenticated/_system/job-queue.tsx +110 -11
- package/src/app/routes/_authenticated/_system/scheduled-tasks.tsx +34 -28
- package/src/app/routes/_authenticated/_tax-categories/components/tax-category-bulk-actions.tsx +15 -0
- package/src/app/routes/_authenticated/_tax-categories/tax-categories.graphql.ts +11 -2
- package/src/app/routes/_authenticated/_tax-categories/tax-categories.tsx +14 -7
- package/src/app/routes/_authenticated/_tax-categories/tax-categories_.$id.tsx +20 -16
- package/src/app/routes/_authenticated/_tax-rates/components/tax-rate-bulk-actions.tsx +15 -0
- package/src/app/routes/_authenticated/_tax-rates/tax-rates.graphql.ts +11 -2
- package/src/app/routes/_authenticated/_tax-rates/tax-rates.tsx +15 -8
- package/src/app/routes/_authenticated/_tax-rates/tax-rates_.$id.tsx +22 -18
- package/src/app/routes/_authenticated/_zones/components/zone-bulk-actions.tsx +15 -0
- package/src/app/routes/_authenticated/_zones/components/zone-countries-sheet.tsx +4 -4
- package/src/app/routes/_authenticated/_zones/components/zone-countries-table.tsx +12 -15
- package/src/app/routes/_authenticated/_zones/zones.graphql.ts +11 -2
- package/src/app/routes/_authenticated/_zones/zones.tsx +13 -6
- package/src/app/routes/_authenticated/_zones/zones_.$id.tsx +18 -14
- package/src/app/routes/_authenticated/index.tsx +6 -6
- package/src/app/routes/_authenticated.tsx +4 -4
- package/src/app/routes/login.tsx +2 -2
- package/src/app/styles.css +5 -2
- package/src/lib/components/data-display/boolean.tsx +1 -1
- package/src/lib/components/data-display/date-time.tsx +9 -3
- package/src/lib/components/data-display/json.tsx +1 -1
- package/src/lib/components/data-display/money.tsx +2 -3
- package/src/lib/components/data-input/affixed-input.tsx +3 -8
- package/src/lib/components/data-input/combination-mode-input.tsx +52 -0
- package/src/lib/components/data-input/configurable-operation-list-input.tsx +433 -0
- package/src/lib/components/data-input/custom-field-list-input.tsx +297 -0
- package/src/lib/components/data-input/customer-group-input.tsx +2 -2
- package/src/lib/components/data-input/datetime-input.tsx +132 -146
- package/src/lib/components/data-input/default-relation-input.tsx +599 -0
- package/src/lib/components/data-input/facet-value-input.tsx +30 -22
- package/src/lib/components/data-input/index.ts +17 -0
- package/src/lib/components/data-input/money-input.tsx +5 -12
- package/src/lib/components/data-input/product-multi-selector.tsx +426 -0
- package/src/lib/components/data-input/relation-input.tsx +164 -0
- package/src/lib/components/data-input/relation-selector.tsx +476 -0
- package/src/lib/components/data-input/{richt-text-input.tsx → rich-text-input.tsx} +15 -9
- package/src/lib/components/data-input/select-with-options.tsx +84 -0
- package/src/lib/components/data-input/struct-form-input.tsx +324 -0
- package/src/lib/components/data-table/add-filter-menu.tsx +9 -18
- package/src/lib/components/data-table/data-table-bulk-action-item.tsx +101 -0
- package/src/lib/components/data-table/data-table-bulk-actions.tsx +108 -0
- package/src/lib/components/data-table/data-table-column-header.tsx +4 -22
- package/src/lib/components/data-table/data-table-faceted-filter.tsx +8 -8
- package/src/lib/components/data-table/data-table-filter-badge.tsx +16 -8
- package/src/lib/components/data-table/data-table-filter-dialog.tsx +8 -8
- package/src/lib/components/data-table/data-table-pagination.tsx +4 -4
- package/src/lib/components/data-table/data-table-utils.ts +34 -0
- package/src/lib/components/data-table/data-table-view-options.tsx +27 -23
- package/src/lib/components/data-table/data-table.tsx +90 -43
- package/src/lib/components/data-table/filters/data-table-boolean-filter.tsx +11 -8
- package/src/lib/components/data-table/filters/data-table-datetime-filter.tsx +14 -23
- package/src/lib/components/data-table/filters/data-table-id-filter.tsx +15 -10
- package/src/lib/components/data-table/filters/data-table-number-filter.tsx +18 -17
- package/src/lib/components/data-table/filters/data-table-string-filter.tsx +29 -12
- package/src/lib/components/data-table/human-readable-operator.tsx +3 -3
- package/src/lib/components/data-table/refresh-button.tsx +30 -15
- package/src/lib/components/data-table/use-generated-columns.tsx +322 -0
- package/src/lib/components/labeled-data.tsx +21 -0
- package/src/lib/components/layout/app-layout.tsx +8 -13
- package/src/lib/components/layout/app-sidebar.tsx +5 -5
- package/src/lib/components/layout/channel-switcher.tsx +171 -62
- package/src/lib/components/layout/content-language-selector.tsx +16 -10
- package/src/lib/components/layout/dev-mode-indicator.tsx +18 -0
- package/src/lib/components/layout/generated-breadcrumbs.tsx +1 -1
- package/src/lib/components/layout/language-dialog.tsx +7 -12
- package/src/lib/components/layout/manage-languages-dialog.tsx +405 -0
- package/src/lib/components/layout/nav-item-wrapper.tsx +107 -0
- package/src/lib/components/layout/nav-main.tsx +200 -111
- package/src/lib/components/layout/nav-projects.tsx +2 -2
- package/src/lib/components/layout/nav-user.tsx +7 -7
- package/src/lib/components/layout/prerelease-popup.tsx +1 -1
- package/src/lib/components/login/login-form.tsx +85 -50
- package/src/lib/components/shared/alerts.tsx +3 -3
- package/src/lib/components/shared/animated-number.tsx +2 -2
- package/src/lib/components/shared/asset/asset-bulk-actions.tsx +109 -0
- package/src/lib/components/shared/asset/asset-focal-point-editor.tsx +29 -19
- package/src/lib/components/shared/asset/asset-gallery.tsx +25 -20
- package/src/lib/components/shared/asset/asset-picker-dialog.tsx +63 -66
- package/src/lib/components/shared/asset/asset-preview-dialog.tsx +3 -7
- package/src/lib/components/shared/asset/asset-preview-selector.tsx +4 -6
- package/src/lib/components/shared/asset/asset-preview.tsx +7 -21
- package/src/lib/components/shared/asset/asset-properties.tsx +7 -9
- package/src/lib/components/shared/asset/focal-point-control.tsx +5 -13
- package/src/lib/components/shared/assign-to-channel-bulk-action.tsx +71 -0
- package/src/lib/components/shared/assign-to-channel-dialog.tsx +155 -0
- package/src/lib/components/shared/assigned-facet-values.tsx +1 -5
- package/src/lib/components/shared/channel-code-label.tsx +3 -4
- package/src/lib/components/shared/channel-selector.tsx +6 -6
- package/src/lib/components/shared/configurable-operation-arg-input.tsx +367 -23
- package/src/lib/components/shared/configurable-operation-input.tsx +87 -48
- package/src/lib/components/shared/configurable-operation-multi-selector.tsx +260 -0
- package/src/lib/components/shared/configurable-operation-selector.tsx +156 -0
- package/src/lib/components/shared/confirmation-dialog.tsx +2 -2
- package/src/lib/components/shared/copyable-text.tsx +3 -4
- package/src/lib/components/shared/country-selector.tsx +21 -18
- package/src/lib/components/shared/currency-selector.tsx +5 -5
- package/src/lib/components/shared/custom-fields-form.tsx +423 -50
- package/src/lib/components/shared/customer-address-form.tsx +18 -13
- package/src/lib/components/shared/customer-group-selector.tsx +6 -6
- package/src/lib/components/shared/customer-selector.tsx +24 -18
- package/src/lib/components/shared/detail-page-button.tsx +45 -1
- package/src/lib/components/shared/entity-assets.tsx +33 -34
- package/src/lib/components/shared/error-page.tsx +6 -6
- package/src/lib/components/shared/facet-value-chip.tsx +12 -5
- package/src/lib/components/shared/facet-value-selector.tsx +64 -63
- package/src/lib/components/shared/form-field-wrapper.tsx +47 -24
- package/src/lib/components/shared/history-timeline/history-entry-date.tsx +37 -0
- package/src/lib/components/shared/history-timeline/history-entry.tsx +146 -70
- package/src/lib/components/shared/history-timeline/history-note-checkbox.tsx +3 -3
- package/src/lib/components/shared/history-timeline/history-note-editor.tsx +4 -4
- package/src/lib/components/shared/history-timeline/history-note-input.tsx +7 -7
- package/src/lib/components/shared/history-timeline/history-timeline.tsx +8 -48
- package/src/lib/components/shared/language-selector.tsx +5 -5
- package/src/lib/components/shared/logo-mark.tsx +2 -2
- package/src/lib/components/shared/multi-select.tsx +6 -6
- package/src/lib/components/shared/navigation-confirmation.tsx +24 -9
- package/src/lib/components/shared/option-value-input.tsx +18 -16
- package/src/lib/components/shared/paginated-list-data-table.tsx +35 -230
- package/src/lib/components/shared/permission-guard.tsx +4 -4
- package/src/lib/components/shared/product-variant-selector.tsx +59 -34
- package/src/lib/components/shared/remove-from-channel-bulk-action.tsx +90 -0
- package/src/lib/components/shared/role-code-label.tsx +10 -6
- package/src/lib/components/shared/role-selector.tsx +4 -4
- package/src/lib/components/shared/seller-selector.tsx +21 -17
- package/src/lib/components/shared/stock-level-label.tsx +5 -5
- package/src/lib/components/shared/tax-category-selector.tsx +5 -5
- package/src/lib/components/shared/translatable-form-field.tsx +46 -23
- package/src/lib/components/shared/vendure-image.tsx +31 -2
- package/src/lib/components/shared/zone-selector.tsx +5 -6
- package/src/lib/components/ui/accordion.tsx +3 -3
- package/src/lib/components/ui/alert-dialog.tsx +10 -10
- package/src/lib/components/ui/alert.tsx +3 -3
- package/src/lib/components/ui/aspect-ratio.tsx +9 -0
- package/src/lib/components/ui/badge.tsx +2 -2
- package/src/lib/components/ui/breadcrumb.tsx +4 -4
- package/src/lib/components/ui/button.tsx +10 -3
- package/src/lib/components/ui/calendar.tsx +392 -459
- package/src/lib/components/ui/card.tsx +2 -2
- package/src/lib/components/ui/carousel.tsx +241 -0
- package/src/lib/components/ui/chart.tsx +351 -0
- package/src/lib/components/ui/checkbox.tsx +2 -2
- package/src/lib/components/ui/command.tsx +12 -6
- package/src/lib/components/ui/context-menu.tsx +252 -0
- package/src/lib/components/ui/dialog.tsx +2 -2
- package/src/lib/components/ui/drawer.tsx +133 -0
- package/src/lib/components/ui/dropdown-menu.tsx +7 -7
- package/src/lib/components/ui/form.tsx +8 -8
- package/src/lib/components/ui/hover-card.tsx +3 -3
- package/src/lib/components/ui/input-otp.tsx +77 -0
- package/src/lib/components/ui/input.tsx +1 -1
- package/src/lib/components/ui/label.tsx +2 -2
- package/src/lib/components/ui/menubar.tsx +274 -0
- package/src/lib/components/ui/navigation-menu.tsx +168 -0
- package/src/lib/components/ui/pagination.tsx +87 -108
- package/src/lib/components/ui/popover.tsx +3 -3
- package/src/lib/components/ui/progress.tsx +29 -0
- package/src/lib/components/ui/radio-group.tsx +45 -0
- package/src/lib/components/ui/resizable.tsx +54 -0
- package/src/lib/components/ui/scroll-area.tsx +2 -2
- package/src/lib/components/ui/select.tsx +151 -129
- package/src/lib/components/ui/separator.tsx +2 -2
- package/src/lib/components/ui/sheet.tsx +5 -5
- package/src/lib/components/ui/sidebar.tsx +10 -10
- package/src/lib/components/ui/skeleton.tsx +1 -1
- package/src/lib/components/ui/slider.tsx +63 -0
- package/src/lib/components/ui/switch.tsx +2 -2
- package/src/lib/components/ui/table.tsx +2 -2
- package/src/lib/components/ui/tabs.tsx +3 -3
- package/src/lib/components/ui/textarea.tsx +1 -1
- package/src/lib/components/ui/toggle-group.tsx +73 -0
- package/src/lib/components/ui/toggle.tsx +45 -0
- package/src/lib/components/ui/tooltip.tsx +3 -3
- package/src/lib/framework/alert/alert-extensions.tsx +2 -3
- package/src/lib/framework/alert/alert-item.tsx +5 -3
- package/src/lib/framework/component-registry/component-registry.tsx +33 -47
- package/src/lib/framework/component-registry/dynamic-component.tsx +3 -3
- package/src/lib/framework/dashboard-widget/base-widget.tsx +5 -13
- package/src/lib/framework/dashboard-widget/latest-orders-widget/index.tsx +8 -8
- package/src/lib/framework/dashboard-widget/latest-orders-widget/latest-orders-widget.graphql.ts +1 -1
- package/src/lib/framework/dashboard-widget/metrics-widget/index.tsx +7 -8
- package/src/lib/framework/dashboard-widget/metrics-widget/metrics-widget.graphql.ts +1 -1
- package/src/lib/framework/dashboard-widget/orders-summary/index.tsx +7 -8
- package/src/lib/framework/dashboard-widget/orders-summary/order-summary-widget.graphql.ts +1 -1
- package/src/lib/framework/dashboard-widget/widget-extensions.tsx +1 -1
- package/src/lib/framework/data-table/data-table-extensions.ts +35 -0
- package/src/lib/framework/defaults.ts +5 -11
- package/src/lib/framework/document-extension/extend-detail-form-query.ts +50 -0
- package/src/lib/framework/document-extension/extend-document.spec.ts +884 -0
- package/src/lib/framework/document-extension/extend-document.ts +159 -0
- package/src/lib/framework/document-introspection/add-custom-fields.ts +50 -2
- package/src/lib/framework/document-introspection/get-document-structure.spec.ts +321 -2
- package/src/lib/framework/document-introspection/get-document-structure.ts +187 -36
- package/src/lib/framework/document-introspection/hooks.ts +4 -1
- package/src/lib/framework/extension-api/define-dashboard-extension.ts +35 -49
- package/src/lib/framework/extension-api/display-component-extensions.tsx +69 -0
- package/src/lib/framework/extension-api/extension-api-types.ts +34 -98
- package/src/lib/framework/extension-api/input-component-extensions.tsx +73 -0
- package/src/lib/framework/extension-api/logic/alerts.ts +10 -0
- package/src/lib/framework/extension-api/logic/data-table.ts +60 -0
- package/src/lib/framework/extension-api/logic/detail-forms.ts +48 -0
- package/src/lib/framework/extension-api/logic/form-components.ts +13 -0
- package/src/lib/framework/extension-api/logic/index.ts +9 -0
- package/src/lib/framework/extension-api/logic/layout.ts +22 -0
- package/src/lib/framework/extension-api/logic/login.ts +17 -0
- package/src/lib/framework/extension-api/logic/navigation.ts +38 -0
- package/src/lib/framework/extension-api/logic/widgets.ts +10 -0
- package/src/lib/framework/extension-api/types/alerts.ts +54 -0
- package/src/lib/framework/extension-api/types/data-table.ts +96 -0
- package/src/lib/framework/extension-api/types/detail-forms.ts +94 -0
- package/src/lib/framework/extension-api/types/form-components.ts +43 -0
- package/src/lib/framework/extension-api/types/index.ts +9 -0
- package/src/lib/framework/extension-api/types/layout.ts +90 -0
- package/src/lib/framework/extension-api/types/login.ts +96 -0
- package/src/lib/framework/extension-api/types/navigation.ts +76 -0
- package/src/lib/framework/extension-api/types/widgets.ts +93 -0
- package/src/lib/framework/extension-api/use-dashboard-extensions.ts +2 -1
- package/src/lib/framework/extension-api/use-login-extensions.ts +26 -0
- package/src/lib/framework/form-engine/custom-form-component-extensions.ts +38 -0
- package/src/lib/framework/form-engine/custom-form-component.tsx +33 -0
- package/src/lib/framework/form-engine/form-schema-tools.spec.ts +472 -0
- package/src/lib/framework/form-engine/form-schema-tools.ts +341 -6
- package/src/lib/framework/form-engine/overridden-form-component.tsx +51 -0
- package/src/lib/framework/form-engine/use-generated-form.tsx +82 -24
- package/src/lib/framework/form-engine/utils.spec.ts +37 -0
- package/src/lib/framework/form-engine/utils.ts +99 -0
- package/src/lib/framework/layout-engine/dev-mode-button.tsx +24 -0
- package/src/lib/framework/layout-engine/layout-extensions.ts +1 -4
- package/src/lib/framework/layout-engine/location-wrapper.tsx +98 -72
- package/src/lib/framework/layout-engine/page-block-provider.tsx +6 -0
- package/src/lib/framework/layout-engine/page-layout.tsx +135 -58
- package/src/lib/framework/page/detail-page-route-loader.tsx +26 -7
- package/src/lib/framework/page/detail-page.tsx +94 -37
- package/src/lib/framework/page/list-page.tsx +18 -11
- package/src/lib/framework/page/use-detail-page.ts +47 -13
- package/src/lib/framework/page/use-extended-router.tsx +4 -5
- package/src/lib/framework/registry/global-registry.ts +4 -0
- package/src/lib/framework/registry/registry-types.ts +17 -5
- package/src/lib/graphql/api.ts +25 -3
- package/src/lib/graphql/common-operations.ts +18 -0
- package/src/lib/graphql/{fragments.tsx → fragments.ts} +1 -2
- package/src/lib/graphql/graphql-env.d.ts +27 -24
- package/src/lib/graphql/settings-store-operations.ts +17 -0
- package/src/lib/hooks/use-auth.tsx +1 -1
- package/src/lib/hooks/use-channel.ts +1 -1
- package/src/lib/hooks/use-extended-detail-query.ts +37 -0
- package/src/lib/hooks/use-extended-list-query.ts +75 -0
- package/src/lib/hooks/use-floating-bulk-actions.ts +82 -0
- package/src/lib/hooks/use-grouped-permissions.ts +3 -2
- package/src/lib/hooks/use-local-format.ts +20 -5
- package/src/lib/hooks/use-page-block.tsx +18 -0
- package/src/lib/hooks/use-page.tsx +2 -2
- package/src/lib/hooks/use-permissions.ts +3 -2
- package/src/lib/hooks/use-server-config.ts +1 -1
- package/src/lib/hooks/use-theme.ts +1 -1
- package/src/lib/hooks/use-user-settings.tsx +1 -1
- package/src/lib/index.ts +85 -7
- package/src/lib/lib/trans.tsx +3 -3
- package/src/lib/lib/utils.ts +52 -1
- package/src/lib/providers/auth.tsx +37 -14
- package/src/lib/providers/channel-provider.tsx +17 -15
- package/src/lib/providers/server-config.tsx +13 -11
- package/src/lib/providers/theme-provider.tsx +2 -3
- package/src/lib/providers/user-settings.tsx +78 -3
- package/src/lib/virtual.d.ts +26 -2
- package/src/vite-env.d.ts +2 -0
- package/vite/tests/barrel-exports.spec.ts +30 -0
- package/vite/tests/fixtures-barrel-exports/my-plugin/index.ts +1 -0
- package/vite/tests/fixtures-barrel-exports/my-plugin/src/my.plugin.ts +8 -0
- package/vite/tests/fixtures-barrel-exports/package.json +6 -0
- package/vite/tests/fixtures-barrel-exports/vendure-config.ts +19 -0
- package/vite/tests/fixtures-npm-plugin/fake_node_modules/test-plugin/index.js +20 -0
- package/vite/tests/fixtures-npm-plugin/fake_node_modules/test-plugin/package.json +8 -0
- package/vite/tests/fixtures-npm-plugin/package.json +6 -0
- package/vite/tests/fixtures-npm-plugin/vendure-config.ts +18 -0
- package/vite/tests/fixtures-path-alias/js-aliased/index.ts +1 -0
- package/vite/tests/fixtures-path-alias/js-aliased/src/js-aliased.plugin.ts +8 -0
- package/vite/tests/fixtures-path-alias/package.json +6 -0
- package/vite/tests/fixtures-path-alias/star-aliased/index.ts +1 -0
- package/vite/tests/fixtures-path-alias/star-aliased/src/star-aliased.plugin.ts +8 -0
- package/vite/tests/fixtures-path-alias/ts-aliased/index.ts +1 -0
- package/vite/tests/fixtures-path-alias/ts-aliased/src/ts-aliased.plugin.ts +8 -0
- package/vite/tests/fixtures-path-alias/vendure-config.ts +20 -0
- package/vite/tests/npm-plugin.spec.ts +46 -0
- package/vite/tests/path-alias.spec.ts +61 -0
- package/vite/tests/tsconfig.json +21 -0
- package/vite/types.ts +44 -0
- package/vite/utils/ast-utils.spec.ts +1 -80
- package/vite/utils/ast-utils.ts +0 -86
- package/vite/utils/compiler.ts +244 -0
- package/vite/utils/config-loader.ts +0 -445
- package/vite/utils/logger.ts +43 -0
- package/vite/utils/plugin-discovery.ts +494 -0
- package/vite/utils/tsconfig-utils.ts +79 -0
- package/vite/utils/ui-config.ts +30 -42
- package/vite/vite-plugin-config-loader.ts +25 -17
- package/vite/vite-plugin-config.ts +6 -7
- package/vite/vite-plugin-dashboard-metadata.ts +27 -16
- package/vite/vite-plugin-tailwind-source.ts +81 -0
- package/vite/vite-plugin-theme.ts +69 -69
- package/vite/vite-plugin-ui-config.ts +119 -17
- package/vite/vite-plugin-vendure-dashboard.ts +60 -16
- package/dist/plugin/utils/ast-utils.js +0 -96
- package/dist/plugin/utils/ast-utils.spec.js +0 -120
- package/dist/plugin/utils/config-loader.d.ts +0 -52
- package/dist/plugin/utils/config-loader.js +0 -343
- package/dist/plugin/utils/ui-config.d.ts +0 -3
- package/dist/plugin/utils/ui-config.js +0 -34
- package/dist/plugin/vite-plugin-theme.js +0 -130
- package/dist/plugin/vite-plugin-ui-config.d.ts +0 -15
- package/dist/plugin/vite-plugin-vendure-dashboard.d.ts +0 -44
- package/src/lib/components/shared/rich-text-editor.tsx +0 -0
- package/src/lib/framework/alert/types.ts +0 -13
- package/src/lib/framework/dashboard-widget/types.ts +0 -22
- /package/dist/{plugin/utils/ast-utils.spec.d.ts → vite/types.js} +0 -0
- /package/dist/{plugin → vite}/utils/schema-generator.d.ts +0 -0
- /package/dist/{plugin → vite}/utils/schema-generator.js +0 -0
- /package/dist/{plugin → vite}/vite-plugin-admin-api-schema.d.ts +0 -0
- /package/dist/{plugin → vite}/vite-plugin-admin-api-schema.js +0 -0
- /package/dist/{plugin → vite}/vite-plugin-config.d.ts +0 -0
- /package/dist/{plugin → vite}/vite-plugin-gql-tada.d.ts +0 -0
- /package/dist/{plugin → vite}/vite-plugin-gql-tada.js +0 -0
- /package/dist/{plugin → vite}/vite-plugin-theme.d.ts +0 -0
- /package/dist/{plugin → vite}/vite-plugin-transform-index.d.ts +0 -0
- /package/dist/{plugin → vite}/vite-plugin-transform-index.js +0 -0
- /package/src/lib/components/data-table/{data-table-types.ts → types.ts} +0 -0
|
@@ -2,27 +2,349 @@ import {
|
|
|
2
2
|
FieldInfo,
|
|
3
3
|
isEnumType,
|
|
4
4
|
isScalarType,
|
|
5
|
-
} from '@/framework/document-introspection/get-document-structure.js';
|
|
5
|
+
} from '@/vdb/framework/document-introspection/get-document-structure.js';
|
|
6
|
+
import { StructCustomFieldConfig } from '@vendure/common/lib/generated-types';
|
|
7
|
+
import { ResultOf } from 'gql.tada';
|
|
6
8
|
import { z, ZodRawShape, ZodType, ZodTypeAny } from 'zod';
|
|
7
9
|
|
|
8
|
-
|
|
10
|
+
import { structCustomFieldFragment } from '../../providers/server-config.js';
|
|
11
|
+
|
|
12
|
+
type CustomFieldConfig = {
|
|
13
|
+
name: string;
|
|
14
|
+
type: string;
|
|
15
|
+
pattern?: string;
|
|
16
|
+
intMin?: number;
|
|
17
|
+
intMax?: number;
|
|
18
|
+
floatMin?: number;
|
|
19
|
+
floatMax?: number;
|
|
20
|
+
datetimeMin?: string;
|
|
21
|
+
datetimeMax?: string;
|
|
22
|
+
list?: boolean;
|
|
23
|
+
nullable?: boolean;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
type StructFieldConfig = ResultOf<typeof structCustomFieldFragment>['fields'][number];
|
|
27
|
+
|
|
28
|
+
function mapGraphQLCustomFieldToConfig(field: StructFieldConfig): CustomFieldConfig {
|
|
29
|
+
const baseConfig = {
|
|
30
|
+
name: field.name,
|
|
31
|
+
type: field.type,
|
|
32
|
+
list: field.list ?? false,
|
|
33
|
+
nullable: true, // Default to true since GraphQL fields are nullable by default
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
switch (field.__typename) {
|
|
37
|
+
case 'StringStructFieldConfig':
|
|
38
|
+
return {
|
|
39
|
+
...baseConfig,
|
|
40
|
+
pattern: field.pattern ?? undefined,
|
|
41
|
+
};
|
|
42
|
+
case 'IntStructFieldConfig':
|
|
43
|
+
return {
|
|
44
|
+
...baseConfig,
|
|
45
|
+
intMin: field.intMin ?? undefined,
|
|
46
|
+
intMax: field.intMax ?? undefined,
|
|
47
|
+
};
|
|
48
|
+
case 'FloatStructFieldConfig':
|
|
49
|
+
return {
|
|
50
|
+
...baseConfig,
|
|
51
|
+
floatMin: field.floatMin ?? undefined,
|
|
52
|
+
floatMax: field.floatMax ?? undefined,
|
|
53
|
+
};
|
|
54
|
+
case 'DateTimeStructFieldConfig':
|
|
55
|
+
return {
|
|
56
|
+
...baseConfig,
|
|
57
|
+
datetimeMin: field.datetimeMin ?? undefined,
|
|
58
|
+
datetimeMax: field.datetimeMax ?? undefined,
|
|
59
|
+
};
|
|
60
|
+
default:
|
|
61
|
+
return baseConfig;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Safely parses a date string into a Date object.
|
|
67
|
+
* Used for parsing datetime constraints in custom field validation.
|
|
68
|
+
*
|
|
69
|
+
* @param dateStr - The date string to parse
|
|
70
|
+
* @returns Parsed Date object or undefined if invalid
|
|
71
|
+
*/
|
|
72
|
+
function parseDate(dateStr: string | undefined | null): Date | undefined {
|
|
73
|
+
if (!dateStr) return undefined;
|
|
74
|
+
const date = new Date(dateStr);
|
|
75
|
+
return isNaN(date.getTime()) ? undefined : date;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Creates a Zod validation schema for datetime fields with optional min/max constraints.
|
|
80
|
+
* Supports both string and Date inputs, which is common in form handling.
|
|
81
|
+
*
|
|
82
|
+
* @param minDate - Optional minimum date constraint
|
|
83
|
+
* @param maxDate - Optional maximum date constraint
|
|
84
|
+
* @returns Zod schema that validates date ranges
|
|
85
|
+
*/
|
|
86
|
+
function createDateValidationSchema(minDate: Date | undefined, maxDate: Date | undefined): ZodType {
|
|
87
|
+
const baseSchema = z.union([z.string(), z.date()]);
|
|
88
|
+
if (!minDate && !maxDate) return baseSchema;
|
|
89
|
+
|
|
90
|
+
const dateMinString = minDate?.toLocaleDateString() ?? '';
|
|
91
|
+
const dateMaxString = maxDate?.toLocaleDateString() ?? '';
|
|
92
|
+
const dateMinMessage = minDate ? `Date must be after ${dateMinString}` : '';
|
|
93
|
+
const dateMaxMessage = maxDate ? `Date must be before ${dateMaxString}` : '';
|
|
94
|
+
|
|
95
|
+
return baseSchema.refine(
|
|
96
|
+
val => {
|
|
97
|
+
if (!val) return true;
|
|
98
|
+
const date = val instanceof Date ? val : new Date(val);
|
|
99
|
+
if (minDate && date < minDate) return false;
|
|
100
|
+
if (maxDate && date > maxDate) return false;
|
|
101
|
+
return true;
|
|
102
|
+
},
|
|
103
|
+
val => {
|
|
104
|
+
const date = val instanceof Date ? val : new Date(val);
|
|
105
|
+
if (minDate && date < minDate) return { message: dateMinMessage };
|
|
106
|
+
if (maxDate && date > maxDate) return { message: dateMaxMessage };
|
|
107
|
+
return { message: '' };
|
|
108
|
+
},
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Creates a Zod validation schema for string fields with optional regex pattern validation.
|
|
114
|
+
* Used for string-type custom fields that may have pattern constraints.
|
|
115
|
+
*
|
|
116
|
+
* @param pattern - Optional regex pattern string for validation
|
|
117
|
+
* @returns Zod string schema with optional pattern validation
|
|
118
|
+
*/
|
|
119
|
+
function createStringValidationSchema(pattern?: string): ZodType {
|
|
120
|
+
let schema = z.string();
|
|
121
|
+
if (pattern) {
|
|
122
|
+
schema = schema.regex(new RegExp(pattern), {
|
|
123
|
+
message: `Value must match pattern: ${pattern}`,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
return schema;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Creates a Zod validation schema for integer fields with optional min/max constraints.
|
|
131
|
+
* Used for int-type custom fields that may have numeric range limits.
|
|
132
|
+
*
|
|
133
|
+
* @param min - Optional minimum value constraint
|
|
134
|
+
* @param max - Optional maximum value constraint
|
|
135
|
+
* @returns Zod number schema with optional range validation
|
|
136
|
+
*/
|
|
137
|
+
function createIntValidationSchema(min?: number, max?: number): ZodType {
|
|
138
|
+
let schema = z.number();
|
|
139
|
+
if (min !== undefined) {
|
|
140
|
+
schema = schema.min(min, {
|
|
141
|
+
message: `Value must be at least ${min}`,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
if (max !== undefined) {
|
|
145
|
+
schema = schema.max(max, {
|
|
146
|
+
message: `Value must be at most ${max}`,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
return schema;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Creates a Zod validation schema for float fields with optional min/max constraints.
|
|
154
|
+
* Used for float-type custom fields that may have numeric range limits.
|
|
155
|
+
*
|
|
156
|
+
* @param min - Optional minimum value constraint
|
|
157
|
+
* @param max - Optional maximum value constraint
|
|
158
|
+
* @returns Zod number schema with optional range validation
|
|
159
|
+
*/
|
|
160
|
+
function createFloatValidationSchema(min?: number, max?: number): ZodType {
|
|
161
|
+
let schema = z.number();
|
|
162
|
+
if (min !== undefined) {
|
|
163
|
+
schema = schema.min(min, {
|
|
164
|
+
message: `Value must be at least ${min}`,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
if (max !== undefined) {
|
|
168
|
+
schema = schema.max(max, {
|
|
169
|
+
message: `Value must be at most ${max}`,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
return schema;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Creates a Zod validation schema for a single custom field based on its type and constraints.
|
|
177
|
+
* This is the main dispatcher that routes different custom field types to their specific
|
|
178
|
+
* validation schema creators. Handles all standard custom field types in Vendure.
|
|
179
|
+
*
|
|
180
|
+
* @param customField - The custom field configuration object
|
|
181
|
+
* @returns Zod schema appropriate for the custom field type
|
|
182
|
+
*/
|
|
183
|
+
function createCustomFieldValidationSchema(customField: CustomFieldConfig): ZodType {
|
|
184
|
+
let zodType: ZodType;
|
|
185
|
+
|
|
186
|
+
switch (customField.type) {
|
|
187
|
+
case 'localeString':
|
|
188
|
+
case 'localeText':
|
|
189
|
+
case 'string':
|
|
190
|
+
zodType = createStringValidationSchema(customField.pattern);
|
|
191
|
+
break;
|
|
192
|
+
case 'int':
|
|
193
|
+
zodType = createIntValidationSchema(customField.intMin, customField.intMax);
|
|
194
|
+
break;
|
|
195
|
+
case 'float':
|
|
196
|
+
zodType = createFloatValidationSchema(customField.floatMin, customField.floatMax);
|
|
197
|
+
break;
|
|
198
|
+
case 'datetime': {
|
|
199
|
+
const minDate = parseDate(customField.datetimeMin);
|
|
200
|
+
const maxDate = parseDate(customField.datetimeMax);
|
|
201
|
+
zodType = createDateValidationSchema(minDate, maxDate);
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
case 'boolean':
|
|
205
|
+
zodType = z.boolean();
|
|
206
|
+
break;
|
|
207
|
+
default:
|
|
208
|
+
zodType = z.any();
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return zodType;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Creates a Zod validation schema for struct-type custom fields.
|
|
217
|
+
* Struct fields contain nested sub-fields, each with their own validation rules.
|
|
218
|
+
* This recursively processes each sub-field to create a nested object schema.
|
|
219
|
+
*
|
|
220
|
+
* @param structFieldConfig - The struct custom field configuration with nested fields
|
|
221
|
+
* @returns Zod object schema representing the struct with all sub-field validations
|
|
222
|
+
*/
|
|
223
|
+
function createStructFieldSchema(structFieldConfig: StructCustomFieldConfig): ZodType {
|
|
224
|
+
if (!structFieldConfig.fields || !Array.isArray(structFieldConfig.fields)) {
|
|
225
|
+
return z.object({}).passthrough();
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const nestedSchema: ZodRawShape = {};
|
|
229
|
+
for (const structSubField of structFieldConfig.fields) {
|
|
230
|
+
const config = mapGraphQLCustomFieldToConfig(structSubField as StructFieldConfig);
|
|
231
|
+
let subFieldType = createCustomFieldValidationSchema(config);
|
|
232
|
+
|
|
233
|
+
// Handle list and nullable for struct sub-fields
|
|
234
|
+
if (config.list) {
|
|
235
|
+
subFieldType = z.array(subFieldType);
|
|
236
|
+
}
|
|
237
|
+
if (config.nullable) {
|
|
238
|
+
subFieldType = subFieldType.optional().nullable();
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
nestedSchema[config.name] = subFieldType;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return z.object(nestedSchema);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Applies common list and nullable modifiers to a Zod schema based on custom field configuration.
|
|
249
|
+
* Many custom fields can be configured as lists (arrays) and/or nullable, so this helper
|
|
250
|
+
* centralizes that logic to avoid duplication.
|
|
251
|
+
*
|
|
252
|
+
* @param zodType - The base Zod schema to modify
|
|
253
|
+
* @param customField - Custom field config containing list/nullable flags
|
|
254
|
+
* @returns Modified Zod schema with list/nullable modifiers applied
|
|
255
|
+
*/
|
|
256
|
+
function applyListAndNullableModifiers(zodType: ZodType, customField: CustomFieldConfig): ZodType {
|
|
257
|
+
let modifiedType = zodType;
|
|
258
|
+
|
|
259
|
+
if (customField.list) {
|
|
260
|
+
modifiedType = z.array(modifiedType);
|
|
261
|
+
}
|
|
262
|
+
if (customField.nullable !== false) {
|
|
263
|
+
modifiedType = modifiedType.optional().nullable();
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return modifiedType;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Processes all custom fields and creates a complete validation schema for the customFields object.
|
|
271
|
+
* Handles context-aware filtering (translation vs root context) and orchestrates the creation
|
|
272
|
+
* of validation schemas for all custom field types including complex struct fields.
|
|
273
|
+
*
|
|
274
|
+
* @param customFieldConfigs - Array of all custom field configurations
|
|
275
|
+
* @param isTranslationContext - Whether we're processing fields for translation forms
|
|
276
|
+
* @returns Zod schema shape for the entire customFields object
|
|
277
|
+
*/
|
|
278
|
+
function processCustomFieldsSchema(
|
|
279
|
+
customFieldConfigs: CustomFieldConfig[],
|
|
280
|
+
isTranslationContext: boolean,
|
|
281
|
+
): ZodRawShape {
|
|
282
|
+
const customFieldsSchema: ZodRawShape = {};
|
|
283
|
+
const translatableTypes = ['localeString', 'localeText'];
|
|
284
|
+
|
|
285
|
+
const filteredCustomFields = customFieldConfigs.filter(cf => {
|
|
286
|
+
if (isTranslationContext) {
|
|
287
|
+
return translatableTypes.includes(cf.type);
|
|
288
|
+
} else {
|
|
289
|
+
return !translatableTypes.includes(cf.type);
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
for (const customField of filteredCustomFields) {
|
|
294
|
+
let zodType: ZodType;
|
|
295
|
+
|
|
296
|
+
if (customField.type === 'struct') {
|
|
297
|
+
zodType = createStructFieldSchema(customField as StructCustomFieldConfig);
|
|
298
|
+
} else {
|
|
299
|
+
zodType = createCustomFieldValidationSchema(customField);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
zodType = applyListAndNullableModifiers(zodType, customField);
|
|
303
|
+
const schemaPropertyName = getGraphQlInputName(customField);
|
|
304
|
+
customFieldsSchema[schemaPropertyName] = zodType;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return customFieldsSchema;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export function createFormSchemaFromFields(
|
|
311
|
+
fields: FieldInfo[],
|
|
312
|
+
customFieldConfigs?: CustomFieldConfig[],
|
|
313
|
+
isTranslationContext = false,
|
|
314
|
+
) {
|
|
9
315
|
const schemaConfig: ZodRawShape = {};
|
|
316
|
+
|
|
10
317
|
for (const field of fields) {
|
|
11
318
|
const isScalar = isScalarType(field.type);
|
|
12
319
|
const isEnum = isEnumType(field.type);
|
|
13
|
-
|
|
14
|
-
|
|
320
|
+
|
|
321
|
+
if ((isScalar || isEnum) && field.name !== 'customFields') {
|
|
322
|
+
schemaConfig[field.name] = getZodTypeFromField(field, customFieldConfigs);
|
|
323
|
+
} else if (field.name === 'customFields') {
|
|
324
|
+
const customFieldsSchema =
|
|
325
|
+
customFieldConfigs && customFieldConfigs.length > 0
|
|
326
|
+
? processCustomFieldsSchema(customFieldConfigs, isTranslationContext)
|
|
327
|
+
: {};
|
|
328
|
+
schemaConfig[field.name] = z.object(customFieldsSchema).optional();
|
|
15
329
|
} else if (field.typeInfo) {
|
|
16
|
-
|
|
330
|
+
const isNestedTranslationContext = field.name === 'translations' || isTranslationContext;
|
|
331
|
+
let nestedType: ZodType = createFormSchemaFromFields(
|
|
332
|
+
field.typeInfo,
|
|
333
|
+
customFieldConfigs,
|
|
334
|
+
isNestedTranslationContext,
|
|
335
|
+
);
|
|
336
|
+
|
|
17
337
|
if (field.nullable) {
|
|
18
338
|
nestedType = nestedType.optional().nullable();
|
|
19
339
|
}
|
|
20
340
|
if (field.list) {
|
|
21
341
|
nestedType = z.array(nestedType);
|
|
22
342
|
}
|
|
343
|
+
|
|
23
344
|
schemaConfig[field.name] = nestedType;
|
|
24
345
|
}
|
|
25
346
|
}
|
|
347
|
+
|
|
26
348
|
return z.object(schemaConfig);
|
|
27
349
|
}
|
|
28
350
|
|
|
@@ -69,8 +391,12 @@ export function getDefaultValueFromField(field: FieldInfo, defaultLanguageCode?:
|
|
|
69
391
|
}
|
|
70
392
|
}
|
|
71
393
|
|
|
72
|
-
export function getZodTypeFromField(field: FieldInfo): ZodTypeAny {
|
|
394
|
+
export function getZodTypeFromField(field: FieldInfo, customFieldConfigs?: CustomFieldConfig[]): ZodTypeAny {
|
|
73
395
|
let zodType: ZodType;
|
|
396
|
+
|
|
397
|
+
// This function is only used for non-custom fields, so we don't need custom field logic here
|
|
398
|
+
// Custom fields are handled separately in createFormSchemaFromFields
|
|
399
|
+
|
|
74
400
|
switch (field.type) {
|
|
75
401
|
case 'String':
|
|
76
402
|
case 'ID':
|
|
@@ -88,6 +414,7 @@ export function getZodTypeFromField(field: FieldInfo): ZodTypeAny {
|
|
|
88
414
|
default:
|
|
89
415
|
zodType = z.any();
|
|
90
416
|
}
|
|
417
|
+
|
|
91
418
|
if (field.list) {
|
|
92
419
|
zodType = z.array(zodType);
|
|
93
420
|
}
|
|
@@ -96,3 +423,11 @@ export function getZodTypeFromField(field: FieldInfo): ZodTypeAny {
|
|
|
96
423
|
}
|
|
97
424
|
return zodType;
|
|
98
425
|
}
|
|
426
|
+
|
|
427
|
+
export function getGraphQlInputName(config: { name: string; type: string; list?: boolean }): string {
|
|
428
|
+
if (config.type === 'relation') {
|
|
429
|
+
return config.list === true ? `${config.name}Ids` : `${config.name}Id`;
|
|
430
|
+
} else {
|
|
431
|
+
return config.name;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DataDisplayComponent,
|
|
3
|
+
DataInputComponent,
|
|
4
|
+
useComponentRegistry,
|
|
5
|
+
} from '@/vdb/framework/component-registry/component-registry.js';
|
|
6
|
+
import { generateInputComponentKey } from '@/vdb/framework/extension-api/input-component-extensions.js';
|
|
7
|
+
import { usePageBlock } from '@/vdb/hooks/use-page-block.js';
|
|
8
|
+
import { usePage } from '@/vdb/hooks/use-page.js';
|
|
9
|
+
import { ControllerRenderProps, FieldPath, FieldValues } from 'react-hook-form';
|
|
10
|
+
|
|
11
|
+
export interface OverriddenFormComponent<
|
|
12
|
+
TFieldValues extends FieldValues = any,
|
|
13
|
+
TName extends FieldPath<TFieldValues> = any,
|
|
14
|
+
> {
|
|
15
|
+
fieldName: string;
|
|
16
|
+
field: ControllerRenderProps<TFieldValues, TName>;
|
|
17
|
+
children?: React.ReactNode;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @description
|
|
22
|
+
* Based on the pageId and blockId of where this is placed, it will check whether any custom components
|
|
23
|
+
* are registered and render them if so. Otherwise, it will render the children, which act as the
|
|
24
|
+
* default if this location has not been overridden.
|
|
25
|
+
*
|
|
26
|
+
* ```tsx
|
|
27
|
+
* <OverriddenFormComponent fieldName="myField" field={field}>
|
|
28
|
+
* <Input {...field} />
|
|
29
|
+
* </OverriddenFormComponent>
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export function OverriddenFormComponent({ fieldName, field, children }: Readonly<OverriddenFormComponent>) {
|
|
33
|
+
const page = usePage();
|
|
34
|
+
const pageBlock = usePageBlock({ optional: true });
|
|
35
|
+
const componentRegistry = useComponentRegistry();
|
|
36
|
+
let DisplayComponent: DataDisplayComponent | undefined;
|
|
37
|
+
let InputComponent: DataInputComponent | undefined;
|
|
38
|
+
if (page.pageId && pageBlock?.blockId) {
|
|
39
|
+
const customInputComponentKey = generateInputComponentKey(page.pageId, pageBlock.blockId, fieldName);
|
|
40
|
+
DisplayComponent = componentRegistry.getDisplayComponent(customInputComponentKey);
|
|
41
|
+
InputComponent = componentRegistry.getInputComponent(customInputComponentKey);
|
|
42
|
+
}
|
|
43
|
+
if (DisplayComponent) {
|
|
44
|
+
return <DisplayComponent {...field} />;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (InputComponent) {
|
|
48
|
+
return <InputComponent {...field} />;
|
|
49
|
+
}
|
|
50
|
+
return children ?? null;
|
|
51
|
+
}
|
|
@@ -1,26 +1,29 @@
|
|
|
1
|
-
import { getOperationVariablesFields } from '@/framework/document-introspection/get-document-structure.js';
|
|
2
|
-
import {
|
|
3
|
-
createFormSchemaFromFields,
|
|
4
|
-
getDefaultValuesFromFields,
|
|
5
|
-
} from '@/framework/form-engine/form-schema-tools.js';
|
|
6
|
-
import { useChannel } from '@/hooks/use-channel.js';
|
|
7
|
-
import { useServerConfig } from '@/hooks/use-server-config.js';
|
|
8
1
|
import type { TypedDocumentNode } from '@graphql-typed-document-node/core';
|
|
9
2
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
10
3
|
import { VariablesOf } from 'gql.tada';
|
|
11
4
|
import { FormEvent } from 'react';
|
|
12
5
|
import { useForm } from 'react-hook-form';
|
|
6
|
+
import { useChannel } from '../../hooks/use-channel.js';
|
|
7
|
+
import { useServerConfig } from '../../hooks/use-server-config.js';
|
|
8
|
+
import { getOperationVariablesFields } from '../document-introspection/get-document-structure.js';
|
|
9
|
+
import { createFormSchemaFromFields, getDefaultValuesFromFields } from './form-schema-tools.js';
|
|
10
|
+
import { removeEmptyIdFields, transformRelationFields } from './utils.js';
|
|
13
11
|
|
|
14
12
|
export interface GeneratedFormOptions<
|
|
15
13
|
T extends TypedDocumentNode<any, any>,
|
|
16
|
-
VarName extends
|
|
14
|
+
VarName extends keyof VariablesOf<T> | undefined = 'input',
|
|
17
15
|
E extends Record<string, any> = Record<string, any>,
|
|
18
16
|
> {
|
|
19
17
|
document?: T;
|
|
20
18
|
varName?: VarName;
|
|
21
19
|
entity: E | null | undefined;
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
customFieldConfig?: any[]; // Add custom field config for validation
|
|
21
|
+
setValues: (
|
|
22
|
+
entity: NonNullable<E>,
|
|
23
|
+
) => VarName extends keyof VariablesOf<T> ? VariablesOf<T>[VarName] : VariablesOf<T>;
|
|
24
|
+
onSubmit?: (
|
|
25
|
+
values: VarName extends keyof VariablesOf<T> ? VariablesOf<T>[VarName] : VariablesOf<T>,
|
|
26
|
+
) => void;
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
/**
|
|
@@ -35,13 +38,19 @@ export function useGeneratedForm<
|
|
|
35
38
|
VarName extends keyof VariablesOf<T> | undefined,
|
|
36
39
|
E extends Record<string, any> = Record<string, any>,
|
|
37
40
|
>(options: GeneratedFormOptions<T, VarName, E>) {
|
|
38
|
-
const { document, entity, setValues, onSubmit, varName } = options;
|
|
41
|
+
const { document, entity, setValues, onSubmit, varName, customFieldConfig } = options;
|
|
39
42
|
const { activeChannel } = useChannel();
|
|
40
|
-
const
|
|
43
|
+
const serverConfig = useServerConfig();
|
|
44
|
+
const availableLanguages = serverConfig?.availableLanguages || [];
|
|
41
45
|
const updateFields = document ? getOperationVariablesFields(document, varName) : [];
|
|
42
|
-
|
|
46
|
+
|
|
47
|
+
const schema = createFormSchemaFromFields(updateFields, customFieldConfig);
|
|
43
48
|
const defaultValues = getDefaultValuesFromFields(updateFields, activeChannel?.defaultLanguageCode);
|
|
44
|
-
const processedEntity = ensureTranslationsForAllLanguages(entity, availableLanguages);
|
|
49
|
+
const processedEntity = ensureTranslationsForAllLanguages(entity, availableLanguages, defaultValues);
|
|
50
|
+
|
|
51
|
+
const values = processedEntity
|
|
52
|
+
? transformRelationFields(updateFields, setValues(processedEntity))
|
|
53
|
+
: defaultValues;
|
|
45
54
|
|
|
46
55
|
const form = useForm({
|
|
47
56
|
resolver: async (values, context, options) => {
|
|
@@ -53,14 +62,28 @@ export function useGeneratedForm<
|
|
|
53
62
|
},
|
|
54
63
|
mode: 'onChange',
|
|
55
64
|
defaultValues,
|
|
56
|
-
values
|
|
65
|
+
values,
|
|
57
66
|
});
|
|
58
|
-
let submitHandler = (event: FormEvent) => {
|
|
67
|
+
let submitHandler = (event: FormEvent): any => {
|
|
59
68
|
event.preventDefault();
|
|
60
69
|
};
|
|
61
70
|
if (onSubmit) {
|
|
62
|
-
submitHandler = (event: FormEvent) => {
|
|
63
|
-
|
|
71
|
+
submitHandler = async (event: FormEvent) => {
|
|
72
|
+
event.preventDefault();
|
|
73
|
+
|
|
74
|
+
// Trigger validation on ALL fields, not just dirty ones
|
|
75
|
+
const isValid = await form.trigger();
|
|
76
|
+
|
|
77
|
+
if (!isValid) {
|
|
78
|
+
console.log(`Form invalid!`);
|
|
79
|
+
event.stopPropagation();
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const onSubmitWrapper = (values: any) => {
|
|
84
|
+
onSubmit(removeEmptyIdFields(values, updateFields));
|
|
85
|
+
};
|
|
86
|
+
form.handleSubmit(onSubmitWrapper)(event);
|
|
64
87
|
};
|
|
65
88
|
}
|
|
66
89
|
|
|
@@ -69,11 +92,13 @@ export function useGeneratedForm<
|
|
|
69
92
|
|
|
70
93
|
/**
|
|
71
94
|
* Ensures that an entity with translations has entries for all available languages.
|
|
72
|
-
* If a language is missing, it creates an empty translation based on the structure of existing translations
|
|
95
|
+
* If a language is missing, it creates an empty translation based on the structure of existing translations
|
|
96
|
+
* and the expected form structure from defaultValues.
|
|
73
97
|
*/
|
|
74
98
|
function ensureTranslationsForAllLanguages<E extends Record<string, any>>(
|
|
75
99
|
entity: E | null | undefined,
|
|
76
100
|
availableLanguages: string[] = [],
|
|
101
|
+
expectedStructure?: Record<string, any>,
|
|
77
102
|
): E | null | undefined {
|
|
78
103
|
if (
|
|
79
104
|
!entity ||
|
|
@@ -91,23 +116,56 @@ function ensureTranslationsForAllLanguages<E extends Record<string, any>>(
|
|
|
91
116
|
// Get existing language codes
|
|
92
117
|
const existingLanguageCodes = new Set(translations.map((t: any) => t.languageCode));
|
|
93
118
|
|
|
119
|
+
// Get the expected translation structure from defaultValues or existing translations
|
|
120
|
+
const existingTemplate = translations[0] || {};
|
|
121
|
+
const expectedTranslationStructure = expectedStructure?.translations?.[0] || {};
|
|
122
|
+
|
|
123
|
+
// Merge the structures to ensure we have all expected fields
|
|
124
|
+
const templateStructure = {
|
|
125
|
+
...expectedTranslationStructure,
|
|
126
|
+
...existingTemplate,
|
|
127
|
+
};
|
|
128
|
+
|
|
94
129
|
// Add missing language translations
|
|
95
130
|
for (const langCode of availableLanguages) {
|
|
96
131
|
if (!existingLanguageCodes.has(langCode)) {
|
|
97
|
-
// Find a translation to use as template for field structure
|
|
98
|
-
const template = translations[0] || {};
|
|
99
132
|
const emptyTranslation: Record<string, any> = {
|
|
100
133
|
languageCode: langCode,
|
|
101
134
|
};
|
|
102
135
|
|
|
103
|
-
// Add empty fields based on template (excluding languageCode)
|
|
104
|
-
Object.keys(
|
|
136
|
+
// Add empty fields based on merged template structure (excluding languageCode)
|
|
137
|
+
Object.keys(templateStructure).forEach(key => {
|
|
105
138
|
if (key !== 'languageCode') {
|
|
106
|
-
|
|
139
|
+
if (typeof templateStructure[key] === 'object' && templateStructure[key] !== null) {
|
|
140
|
+
// For nested objects like customFields, create an empty object
|
|
141
|
+
emptyTranslation[key] = Array.isArray(templateStructure[key]) ? [] : {};
|
|
142
|
+
} else {
|
|
143
|
+
// For primitive values, use empty string as default
|
|
144
|
+
emptyTranslation[key] = '';
|
|
145
|
+
}
|
|
107
146
|
}
|
|
108
147
|
});
|
|
109
148
|
|
|
110
149
|
translations.push(emptyTranslation);
|
|
150
|
+
} else {
|
|
151
|
+
// For existing translations, ensure they have all expected fields
|
|
152
|
+
const existingTranslation = translations.find((t: any) => t.languageCode === langCode);
|
|
153
|
+
if (existingTranslation) {
|
|
154
|
+
Object.keys(expectedTranslationStructure).forEach(key => {
|
|
155
|
+
if (key !== 'languageCode' && !(key in existingTranslation)) {
|
|
156
|
+
if (
|
|
157
|
+
typeof expectedTranslationStructure[key] === 'object' &&
|
|
158
|
+
expectedTranslationStructure[key] !== null
|
|
159
|
+
) {
|
|
160
|
+
existingTranslation[key] = Array.isArray(expectedTranslationStructure[key])
|
|
161
|
+
? []
|
|
162
|
+
: {};
|
|
163
|
+
} else {
|
|
164
|
+
existingTranslation[key] = '';
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
}
|
|
111
169
|
}
|
|
112
170
|
}
|
|
113
171
|
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { graphql, VariablesOf } from 'gql.tada';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
|
|
4
|
+
import { getOperationVariablesFields } from '../document-introspection/get-document-structure.js';
|
|
5
|
+
|
|
6
|
+
import { removeEmptyIdFields } from './utils.js';
|
|
7
|
+
|
|
8
|
+
const createProductDocument = graphql(`
|
|
9
|
+
mutation CreateProduct($input: CreateProductInput!) {
|
|
10
|
+
createProduct(input: $input) {
|
|
11
|
+
id
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
`);
|
|
15
|
+
|
|
16
|
+
type CreateProductInput = VariablesOf<typeof createProductDocument>;
|
|
17
|
+
|
|
18
|
+
describe('removeEmptyIdFields', () => {
|
|
19
|
+
it('should remove empty translation id field', () => {
|
|
20
|
+
const values: CreateProductInput = {
|
|
21
|
+
input: { translations: [{ id: '', languageCode: 'en' }] },
|
|
22
|
+
};
|
|
23
|
+
const fields = getOperationVariablesFields(createProductDocument);
|
|
24
|
+
const result = removeEmptyIdFields(values, fields);
|
|
25
|
+
|
|
26
|
+
expect(result).toEqual({ input: { translations: [{ languageCode: 'en' }] } });
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should remove empty featuredAsset id field', () => {
|
|
30
|
+
const values: CreateProductInput = {
|
|
31
|
+
input: { featuredAssetId: '', translations: [] },
|
|
32
|
+
};
|
|
33
|
+
const fields = getOperationVariablesFields(createProductDocument);
|
|
34
|
+
const result = removeEmptyIdFields(values, fields);
|
|
35
|
+
expect(result).toEqual({ input: { translations: [] } });
|
|
36
|
+
});
|
|
37
|
+
});
|